Repository: flax-lang/flax Branch: master Commit: 9c46e51d8983 Files: 272 Total size: 3.2 MB Directory structure: gitextract_y7d5awgq/ ├── .github/ │ └── workflows/ │ └── continuous_integration.yml ├── .gitignore ├── .semaphore/ │ └── semaphore.yml ├── LICENSE ├── Makefile ├── README.md ├── appveyor.yml ├── build/ │ ├── a.flx │ ├── b.flx │ ├── c.flx │ ├── d.flx │ ├── generate_test.py │ ├── gltest.flx │ ├── old/ │ │ └── raii_poc.flx │ ├── run-test.ps1 │ ├── speed-test.py │ ├── supertiny.flx │ ├── tester.flx │ ├── tests/ │ │ ├── anytest.flx │ │ ├── arraytest.flx │ │ ├── basic.flx │ │ ├── classes.flx │ │ ├── decomposition.flx │ │ ├── defertest.flx │ │ ├── fizzbuzz.flx │ │ ├── forloops.flx │ │ ├── functions.flx │ │ ├── generics.flx │ │ ├── intlimits.flx │ │ ├── linkedlist.flx │ │ ├── misc.flx │ │ ├── operators.flx │ │ ├── recursiveFib.flx │ │ ├── scopes.flx │ │ ├── slices.flx │ │ ├── unions.flx │ │ └── using.flx │ ├── tiniest.flx │ ├── tmp/ │ │ ├── repro_1.flx │ │ ├── repro_2.flx │ │ └── repro_3.flx │ ├── tmp2/ │ │ ├── a.flx │ │ ├── b.flx │ │ └── c.flx │ └── ultratiny.flx ├── changelog.md ├── external/ │ ├── mpreal/ │ │ └── mpreal.h │ ├── tinyprocesslib/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── process.cpp │ │ ├── process_os.cpp │ │ ├── process_unix.inc │ │ ├── process_win.inc │ │ └── tinyprocess.h │ └── utf8rewind/ │ ├── LICENSE │ ├── README.md │ ├── include/ │ │ └── utf8rewind/ │ │ └── utf8rewind.h │ ├── makefile │ └── source/ │ ├── internal/ │ │ ├── base.h │ │ ├── casemapping.c │ │ ├── casemapping.h │ │ ├── codepoint.c │ │ ├── codepoint.h │ │ ├── composition.c │ │ ├── composition.h │ │ ├── database.c │ │ ├── database.h │ │ ├── decomposition.c │ │ ├── decomposition.h │ │ ├── seeking.c │ │ ├── seeking.h │ │ ├── streaming.c │ │ └── streaming.h │ ├── unicodedatabase.c │ ├── unicodedatabase.h │ └── utf8rewind.c ├── issues.md ├── libs/ │ ├── OpenGL/ │ │ ├── GL.flx │ │ └── GLUT.flx │ ├── SDL2/ │ │ ├── Keyboard.flx │ │ └── SDL.flx │ ├── libc.flx │ ├── os.flx │ └── std/ │ ├── file.flx │ ├── io.flx │ ├── limits.flx │ ├── map.flx │ ├── math.flx │ ├── opt.flx │ ├── print.flx │ └── set.flx ├── meson.build ├── notes.md ├── programs/ │ └── fic/ │ ├── main.flx │ └── run.bat ├── roadmap.md └── source/ ├── backend/ │ ├── backend.cpp │ ├── interp/ │ │ └── driver.cpp │ ├── llvm/ │ │ ├── jit.cpp │ │ ├── linker.cpp │ │ └── translator.cpp │ └── x64AsmBackend.cpp ├── codegen/ │ ├── alloc.cpp │ ├── arithmetic.cpp │ ├── assign.cpp │ ├── autocasting.cpp │ ├── builtin.cpp │ ├── call.cpp │ ├── classes.cpp │ ├── codegenstate.cpp │ ├── constructor.cpp │ ├── controlflow.cpp │ ├── destructure.cpp │ ├── directives.cpp │ ├── dotop.cpp │ ├── enums.cpp │ ├── function.cpp │ ├── glue/ │ │ ├── any.cpp │ │ ├── arrays.cpp │ │ ├── misc.cpp │ │ ├── saa_common.cpp │ │ └── strings.cpp │ ├── literals.cpp │ ├── logical.cpp │ ├── loops.cpp │ ├── misc.cpp │ ├── operators.cpp │ ├── raii.cpp │ ├── ranges.cpp │ ├── refcounting.cpp │ ├── sizeof.cpp │ ├── slice.cpp │ ├── structs.cpp │ ├── subscript.cpp │ ├── toplevel.cpp │ ├── traits.cpp │ ├── unions.cpp │ └── variable.cpp ├── fir/ │ ├── ConstantValue.cpp │ ├── Function.cpp │ ├── GlobalValue.cpp │ ├── IRBlock.cpp │ ├── IRBuilder.cpp │ ├── Instruction.cpp │ ├── Module.cpp │ ├── Name.cpp │ ├── Types/ │ │ ├── ArraySliceType.cpp │ │ ├── ArrayType.cpp │ │ ├── ClassType.cpp │ │ ├── DynamicArrayType.cpp │ │ ├── EnumType.cpp │ │ ├── FunctionType.cpp │ │ ├── OpaqueType.cpp │ │ ├── PointerType.cpp │ │ ├── PrimitiveType.cpp │ │ ├── RawUnionType.cpp │ │ ├── SingleTypes.cpp │ │ ├── StructType.cpp │ │ ├── TraitType.cpp │ │ ├── TupleType.cpp │ │ ├── Type.cpp │ │ ├── TypeUtils.cpp │ │ └── UnionType.cpp │ ├── Value.cpp │ └── interp/ │ ├── compiler.cpp │ ├── interpreter.cpp │ └── wrappers.cpp ├── frontend/ │ ├── arguments.cpp │ ├── collector.cpp │ ├── dependencies.cpp │ ├── errors.cpp │ ├── file.cpp │ ├── import.cpp │ ├── lexer.cpp │ ├── parser/ │ │ ├── controlflow.cpp │ │ ├── expr.cpp │ │ ├── function.cpp │ │ ├── literal.cpp │ │ ├── misc.cpp │ │ ├── operators.cpp │ │ ├── toplevel.cpp │ │ ├── type.cpp │ │ └── variable.cpp │ └── pts.cpp ├── include/ │ ├── allocator.h │ ├── ast.h │ ├── backend.h │ ├── backends/ │ │ ├── interp.h │ │ └── llvm.h │ ├── codegen.h │ ├── container.h │ ├── defs.h │ ├── errors.h │ ├── frontend.h │ ├── gluecode.h │ ├── ir/ │ │ ├── block.h │ │ ├── constant.h │ │ ├── function.h │ │ ├── instruction.h │ │ ├── interp.h │ │ ├── irbuilder.h │ │ ├── module.h │ │ ├── type.h │ │ └── value.h │ ├── lexer.h │ ├── memorypool.h │ ├── parser.h │ ├── parser_internal.h │ ├── platform.h │ ├── polymorph.h │ ├── precompile.h │ ├── pts.h │ ├── repl.h │ ├── resolver.h │ ├── sst.h │ ├── sst_expr.h │ ├── stcommon.h │ ├── string_consts.h │ ├── typecheck.h │ ├── zfu.h │ ├── zpr.h │ └── ztmu.h ├── main.cpp ├── misc/ │ ├── allocator.cpp │ ├── destructors.cpp │ ├── identifier.cpp │ └── mpool.cpp ├── platform/ │ ├── backtrace.cpp │ ├── compiler.cpp │ ├── msvcfinder.cpp │ └── platform.cpp ├── repl/ │ ├── commands.cpp │ ├── driver.cpp │ ├── execute.cpp │ └── history.cpp └── typecheck/ ├── alloc.cpp ├── arithmetic.cpp ├── assign.cpp ├── call.cpp ├── classes.cpp ├── controlflow.cpp ├── defer.cpp ├── destructure.cpp ├── directives.cpp ├── dotop.cpp ├── enums.cpp ├── function.cpp ├── literals.cpp ├── loops.cpp ├── misc.cpp ├── operators.cpp ├── polymorph/ │ ├── driver.cpp │ ├── instantiator.cpp │ ├── misc.cpp │ ├── solver.cpp │ └── transforms.cpp ├── ranges.cpp ├── resolver/ │ ├── driver.cpp │ ├── misc.cpp │ └── resolver.cpp ├── sizeof.cpp ├── slice.cpp ├── special.cpp ├── structs.cpp ├── subscript.cpp ├── toplevel.cpp ├── traits.cpp ├── type.cpp ├── typecheckstate.cpp ├── unions.cpp ├── using.cpp └── variable.cpp ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/continuous_integration.yml ================================================ name: CI on: [push, pull_request] jobs: build-linux: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v1 - name: install dependencies run: | sudo echo "deb https://apt.llvm.org/bionic/ llvm-toolchain-bionic-11 main" | sudo tee -a /etc/apt/sources.list sudo wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - sudo apt -y update sudo apt-get -o Dpkg::Options::="--force-overwrite" --allow-unauthenticated -y install -y g++-9 llvm-11 llvm-11-dev libllvm11 libmpfr-dev libmpfr6 - name: build env: LLVM_CONFIG: llvm-config-11 CC: gcc-9 CXX: g++-9 run: make -j2 build - name: jit/llvm run: build/sysroot/usr/local/bin/flaxc -sysroot build/sysroot -profile --ffi-escape -run -backend llvm build/tester.flx - name: jit/interp run: build/sysroot/usr/local/bin/flaxc -sysroot build/sysroot -profile --ffi-escape -run -backend interp build/tester.flx - name: compile/llvm run: build/sysroot/usr/local/bin/flaxc -sysroot build/sysroot -profile --ffi-escape build/tester.flx && ./tester build-macos: runs-on: macOS-10.15 steps: - uses: actions/checkout@v1 - name: install dependencies run: | brew install mpfr llvm pkg-config - name: build env: LLVM_CONFIG: /usr/local/opt/llvm/bin/llvm-config run: PATH="$PATH:$(pwd)/llvm/11.0.0/bin" make -j2 build - name: jit/llvm run: build/sysroot/usr/local/bin/flaxc -sysroot build/sysroot -profile --ffi-escape -run -backend llvm build/tester.flx - name: jit/interp run: build/sysroot/usr/local/bin/flaxc -sysroot build/sysroot -profile --ffi-escape -run -backend interp build/tester.flx - name: compile/llvm run: build/sysroot/usr/local/bin/flaxc -sysroot build/sysroot -profile --ffi-escape build/tester.flx && ./tester build-windows: runs-on: windows-2019 env: MPIR_ROOT_DIR: C:/tmp/lib/mpir MPFR_ROOT_DIR: C:/tmp/lib/mpfr LLVM_ROOT_DIR: C:/tmp/lib/llvm LIBFFI_ROOT_DIR: C:/tmp/lib/libffi ACTIONS_ALLOW_UNSECURE_COMMANDS: true steps: - uses: seanmiddleditch/gha-setup-ninja@v1 - uses: seanmiddleditch/gha-setup-vsdevenv@master - uses: actions/checkout@v1 - name: cache libraries uses: actions/cache@v1.0.0 id: cache-libs with: path: C:/tmp/lib key: cached-libs - name: download libraries if: steps.cache-libs.outputs.cache-hit != 'true' run: | echo "root dirs:" $LLVM_ROOT_DIR echo "extraction: C:\tmp\lib" Invoke-WebRequest 'https://github.com/flax-lang/flax/releases/download/win-build-deps/libraries.zip' -OutFile 'libs.zip' 7z x -y -o"C:\tmp\lib" libs.zip - name: install meson run: pip install meson - name: build run: | meson --buildtype=release build/meson-rel ninja -C build/meson-rel - name: copy stdlib run: | New-Item -Force -Path build\sysroot\usr\local\lib\flaxlibs -ItemType Directory Copy-Item -Recurse -Force libs\* build\sysroot\usr\local\lib\flaxlibs\ - name: jit/llvm run: build\meson-rel\flaxc.exe -sysroot build\sysroot -run -backend llvm --ffi-escape build\tester.flx - name: jit/interp run: build\meson-rel\flaxc.exe -sysroot build\sysroot -run -backend interp --ffi-escape build\tester.flx - name: compile/llvm run: | build\meson-rel\flaxc.exe -sysroot build\sysroot --ffi-escape build\tester.flx .\tester.exe ================================================ FILE: .gitignore ================================================ # Compiled Object files *.slo *.lo *.o *.obj # Precompiled Headers *.gch* *.pch* # Makefile dependencies *.cpp.d *.c.d *.h.d # Compiled Dynamic libraries *.so *.dylib *.dll # Fortran module files *.mod # Compiled Static libraries *.lai *.la *.a *.lib # Executables *.exe *.out *.app *.pdb # profile data *.profdata *.profraw # overrides: commit run *.sublime-* build/sysroot build/meson-* .modifydates build/test build/gltest build/standalone *.ll *.bc build/plots.txt build/massive.flx *.ir shakefile.hi shakefile .shake.database checker-276 countloc .shake.lock bug-repro .clang_complete *.code-workspace .vscode *.vcxproj.filters *.vcxproj.user countloc.bat builddir prof.svg prof_with_square.svg build/cmake-output .idea # CMakeLists.txt .flax-repl-history docs/.antlr codealike.json build/test build/tester build/supertiny build/gltest release.fish macosx.zip flax.config flax.creator flax.creator.user flax.files flax.includes .vs/ build/__pycache__ *.vspx .cache compile_flags.txt ================================================ FILE: .semaphore/semaphore.yml ================================================ version: v1.0 name: flax agent: machine: type: e1-standard-2 os_image: ubuntu1804 blocks: - name: "linux-build" task: agent: machine: type: e1-standard-2 os_image: ubuntu1804 jobs: - name: build commands: - checkout - sudo echo "deb https://apt.llvm.org/bionic/ llvm-toolchain-bionic-11 main" | sudo tee -a /etc/apt/sources.list - sudo wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - sudo apt -y update - sudo apt-get -o Dpkg::Options::="--force-overwrite" --allow-unauthenticated -y install -y llvm-11 llvm-11-dev libllvm11 libmpfr-dev libmpfr6 - CXX=g++-8 CC=gcc-8 LLVM_CONFIG=llvm-config-11 make -j2 build - build/sysroot/usr/local/bin/flaxc -sysroot build/sysroot -profile --ffi-escape -run -backend llvm build/tester.flx - build/sysroot/usr/local/bin/flaxc -sysroot build/sysroot -profile --ffi-escape -run -backend interp build/tester.flx - build/sysroot/usr/local/bin/flaxc -sysroot build/sysroot -profile --ffi-escape build/tester.flx && ./tester ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2015 zhiayang Licensed 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. ================================================ FILE: Makefile ================================================ # Makefile for Orion-X3/Orion-X4/mx and derivatives # Written in 2011 # This makefile is licensed under the WTFPL WARNINGS := -Wno-unused-parameter -Wno-sign-conversion -Wno-padded -Wno-conversion -Wno-shadow -Wno-missing-noreturn -Wno-unused-macros -Wno-switch-enum -Wno-deprecated -Wno-format-nonliteral -Wno-trigraphs -Wno-unused-const-variable -Wdeprecated-declarations -Werror=return-type GCCWARNINGS := -Wno-init-list-lifetime CLANGWARNINGS := -Wno-undefined-func-template -Wno-comma -Wno-nullability-completeness -Wno-redundant-move -Wno-nested-anon-types -Wno-gnu-anonymous-struct -Wno-reserved-id-macro -Wno-extra-semi -Wno-gnu-zero-variadic-macro-arguments -Wno-shift-sign-overflow -Wno-exit-time-destructors -Wno-global-constructors -Wno-c++98-compat-pedantic -Wno-documentation-unknown-command -Wno-weak-vtables -Wno-c++98-compat -Wold-style-cast SYSROOT := build/sysroot PREFIX := usr/local OUTPUTBIN := flaxc OUTPUT := $(SYSROOT)/$(PREFIX)/bin/$(OUTPUTBIN) CC ?= "clang" CXX ?= "clang++" LLVM_CONFIG ?= "llvm-config" CXXSRC := $(shell find source external/tinyprocesslib -iname "*.cpp") CXXOBJ := $(CXXSRC:.cpp=.cpp.o) CXXDEPS := $(CXXSRC:.cpp=.cpp.d) PRECOMP_HDRS := source/include/precompile.h PRECOMP_GCH := $(PRECOMP_HDRS:.h=.h.gch) FLXLIBLOCATION := $(SYSROOT)/$(PREFIX)/lib FLXSRC := $(shell find libs -iname "*.flx") NUMFILES := $$(($(words $(CXXSRC)))) DEFINES := -D__USE_MINGW_ANSI_STDIO=1 SANITISE := CXXFLAGS += -std=c++17 -fvisibility=hidden -O0 -g -c -Wall -frtti -fno-omit-frame-pointer $(SANITISE) $(DEFINES) LDFLAGS += $(SANITISE) -fvisibility=hidden UNAME_IDENT := $(shell uname) COMPILER_IDENT := $(shell $(CC) --version | head -n 1) ifeq ("$(UNAME_IDENT)","Darwin") LIBFFI_CFLAGS := $(shell env PKG_CONFIG_PATH=/usr/local/opt/libffi/lib/pkgconfig pkg-config --cflags libffi) LIBFFI_LDFLAGS := $(shell env PKG_CONFIG_PATH=/usr/local/opt/libffi/lib/pkgconfig pkg-config --libs libffi) else LIBFFI_CFLAGS := $(shell pkg-config --cflags libffi) LIBFFI_LDFLAGS := $(shell pkg-config --libs libffi) # on linux, we need to explicitly export our functions # like __declspec(dllexport) except __attribute__((visibility("default"))) LDFLAGS += -Wl,--export-dynamic endif MPFR_CFLAGS := $(shell pkg-config --cflags mpfr) MPFR_LDFLAGS := $(shell pkg-config --libs mpfr) CXXFLAGS += $(MPFR_CFLAGS) $(LIBFFI_CFLAGS) LDFLAGS += $(MPFR_LDFLAGS) $(LIBFFI_LDFLAGS) ENABLE_CODE_COVERAGE ?= "yes" ifneq (,$(findstring clang,$(COMPILER_IDENT))) CXXFLAGS += -Xclang -fcolor-diagnostics $(SANITISE) $(CLANGWARNINGS) ifeq ("$(ENABLE_CODE_COVERAGE)","yes") CXXFLAGS += -fprofile-instr-generate -fcoverage-mapping LDFLAGS += -fprofile-instr-generate -fcoverage-mapping endif else CXXFLAGS += $(GCCWARNINGS) ifeq ("$(ENABLE_CODE_COVERAGE)","yes") CXXFLAGS += -fprofile-arcs -ftest-coverage LDFLAGS += -lgcov endif endif UTF8REWIND_AR := external/libutf8rewind.a FLXFLAGS += -sysroot $(SYSROOT) --ffi-escape SUPERTINYBIN := build/supertiny GLTESTBIN := build/gltest TESTBIN := build/tester SUPERTINYSRC := build/supertiny.flx GLTESTSRC := build/gltest.flx TESTSRC := build/tester.flx .DEFAULT_GOAL = jit -include $(CXXDEPS) -include source/include/precompile.h.d .PHONY: copylibs jit compile clean build linux ci satest tiny satest: build @$(OUTPUT) $(FLXFLAGS) -run build/standalone.flx tester: build @$(OUTPUT) $(FLXFLAGS) -run build/tester.flx ci: test jit: build @$(OUTPUT) $(FLXFLAGS) -run -o $(SUPERTINYBIN) $(SUPERTINYSRC) compile: build @$(OUTPUT) $(FLXFLAGS) -o $(SUPERTINYBIN) $(SUPERTINYSRC) -lm test: build @$(OUTPUT) $(FLXFLAGS) -run -o $(TESTBIN) $(TESTSRC) repl: build @$(OUTPUT) $(FLXFLAGS) -repl gltest: build @$(OUTPUT) $(FLXFLAGS) -run -framework GLUT -framework OpenGL -lsdl2 -o $(GLTESTBIN) $(GLTESTSRC) build1: build: build1 $(OUTPUT) copylibs # built build/%.flx: build @$(OUTPUT) $(FLXFLAGS) -run -profile $@ copylibs: $(FLXSRC) @mkdir -p $(FLXLIBLOCATION)/flaxlibs @cp -R libs $(FLXLIBLOCATION)/ @rm -r $(FLXLIBLOCATION)/flaxlibs @mv $(FLXLIBLOCATION)/libs $(FLXLIBLOCATION)/flaxlibs $(OUTPUT): $(PRECOMP_GCH) $(CXXOBJ) $(COBJ) $(UTF8REWIND_AR) @printf "# linking\n" @mkdir -p $(dir $(OUTPUT)) @$(CXX) -o $@ $(CXXOBJ) $(COBJ) $(LDFLAGS) -Lexternal -L$(shell $(LLVM_CONFIG) --prefix)/lib $(shell $(LLVM_CONFIG) --system-libs --libs core engine native linker bitwriter lto vectorize all-targets object orcjit) -lmpfr -lgmp -lpthread -ldl -lffi -lutf8rewind %.cpp.o: %.cpp @$(eval DONEFILES += "CPP") @printf "# compiling [$(words $(DONEFILES))/$(NUMFILES)] $<\n" @$(CXX) $(CXXFLAGS) $(WARNINGS) -include source/include/precompile.h -Isource/include -Iexternal -I$(shell $(LLVM_CONFIG) --includedir) -MMD -MP -o $@ $< %.h.gch: %.h @printf "# precompiling header $<\n" @$(CXX) $(CXXFLAGS) $(WARNINGS) -o $@ $< -MMD -MP $(UTF8REWIND_AR): @$(MAKE) -C external/utf8rewind all # haha clena: clean clean: @rm -f $(OUTPUT) @find source -name "*.o" | xargs rm -f @find source -name "*.gch*" | xargs rm -f @find source -name "*.pch*" | xargs rm -f @find source -name "*.c.m" | xargs rm -f @find source -name "*.c.d" | xargs rm -f @find source -name "*.cpp.m" | xargs rm -f @find source -name "*.cpp.d" | xargs rm -f ================================================ FILE: README.md ================================================ # [Flax](https://flax-lang.github.io) A low level, general-purpose language with high level syntax and expressibility. [![forthebadge](https://forthebadge.com/images/badges/made-with-crayons.svg)](http://forthebadge.com) [![forthebadge](https://forthebadge.com/images/badges/built-with-resentment.svg)](http://forthebadge.com) [![build status](https://ci.appveyor.com/api/projects/status/c9cmm08t27ef1hji/branch/master?svg=true)](https://ci.appveyor.com/project/zhiayang/flax/branch/master)      [![build status](https://github.com/flax-lang/flax/workflows/CI/badge.svg)](https://github.com/flax-lang/flax/actions)      [![Build Status](https://semaphoreci.com/api/v1/zhiayang/flax/branches/master/badge.svg)](https://semaphoreci.com/zhiayang/flax) ----------------------------------------------- #### Disclaimer #### I work on Flax in my spare time, and as the lone developer I cannot guarantee continuous development. I'm no famous artist but this is my magnum opus, so it'll not be abandoned anytime soon. ### Language Goals - No header files. - Minimal runtime - Minimal stupidity - Clean, expressive syntax ----------------------------------------------- ### Current Features - Structs, unions, enums - Arrays (fixed and dynamic), slices - Pointer manipulation/arithmetic - Operator overloading - Generic functions and types - Type inference (including for generics) - Full compile-time execution (of arbitrary code) - Classes, including virtual dispatch and (single) inheritance ----------------------------------------------- ### Language Syntax - We don't have a proper place that documents everything yet, but most of the basic stuff is probably not gonna change much. The testing code in `build/tests/` (most of them, anyway — check `tester.flx` to see which ones we call) tests basically 90% of the language, so that's the syntax reference for now. - Yes, the syntax is not "officially" defined by a grammar. The reference parser implementation is the One True Definition, for now. ----------------------------------------------- ### Code Sample ```rust import std::io as _ @entry fn main() { println("hello, world!") } ``` ```rust do { fn prints(m: T, a: [U: ...]) { for x in a => printf(" %.2d", m * x) } printf("set 6:") let xs = [ 1, 2, 3, 4, 5 ] prints(3, ...xs) printf("\n") } do { union option { some: T none } let x = option::some("foobar") let y = option::some(456) println("x = %, y = %", x as some, y as some) } ``` ----------------------------------------------- ### Building the Flax compiler #### Dependencies #### - LLVM 11, mostly due to their obsession with changing the IR interface every damn version - GMP/MPIR - MPFR - libffi #### macOS / Linux - The `makefile` is the preferred way to build on UNIX systems. - LLVM needs to be installed. On macOS, `brew install llvm` should work, and you might need to do some PPA fiddling for Debian-based distros. - A C++17-compatible compiler should be used. - Find the `flaxc` executable in `build/sysroot/usr/local/bin`. - Additionally, the (admittedly limited) standard library will be copied from `./libs` to `./build/sysroot/usr/local/lib/flaxlibs/`. #### Windows - Install [meson](https://mesonbuild.com/). - Run `env MPIR_ROOT_DIR=... LLVM_ROOT_DIR=... meson meson-build-dir` to set the locations for the dependencies (see `meson.build` for the names, there are 4) and configure the build. - Optionally, pass `--buildtype=release` to build a release-mode compiler (highly recommended). - Run `ninja -C meson-build-dir`. - `flaxc.exe` will be found in the build directory. ##### Libraries - Download the [prebuilt binaries](https://github.com/flax-lang/flax/releases/tag/win-build-deps) for the 4 dependencies, and place them somewhere. - Note: the folder structure of the libraries should be `(llvm|mpir|mpfr|libffi)/(Release|Debug)/(include|lib)/...`. ----------------------------------------------- ### Building Flax Programs Since nobody in their right mind is *actually* using this, please pass `-sysroot build/sysroot` to invocations of the compiler -- else the compiler will default to looking somewhere in `/usr/local/lib` for libraries. Speaking of which, standard libraries are looked for in `//lib/flaxlibs/`. Prefix is set to `/usr/local/` by default. Since version 0.41.2, executables can be generated on all 3 of our supported platforms! For Linux and macOS, all that is required is a working C compiler in the `$PATH`; we call `cc` to link object files. For Windows, even if you are not building the compiler from source (eg. you are using a released binary), Visual Studio 2017 or newer must still be installed, with the "Desktop development with C++", "MSVC v142 (or whatever)", and "Windows 10 SDK" components. However, we currently find the toolchain through [established means](https://gist.github.com/machinamentum/a2b587a68a49094257da0c39a6c4405f), so that `link.exe` does not have to be in the `%PATH%`, ie. you do not have to call `vcvarsall.bat` before running the compiler. ----------------------------------------------- ### Contributors Special thanks to the Unofficial Official Language Consultants: [darkf](https://github.com/darkf), [adrian17](https://github.com/adrian17), [sim642](https://github.com/sim642), and [ryu0](https://github.com/ryu0). ### Contributing Feel free to open an issue if you feel that there's any missing feature, or if you found a bug in the compiler. Pull requests are also welcome. ### Licensing The Flax compiler itself (this repository) is licensed under the Apache 2.0 license (see `LICENSE` file). For ease of building, some dependencies are included in the repository itself (under the `external` folder) and compiled together, instead of as a separate library (shared or otherwise). These are: 1. [mpreal](https://bitbucket.org/advanpix/mpreal), GPL 2. [utf8rewind](https://bitbucket.org/knight666/utf8rewind), MIT 3. [tinyprocesslib](https://gitlab.com/eidheim/tiny-process-library), MIT ================================================ FILE: appveyor.yml ================================================ image: Visual Studio 2019 clone_depth: 50 clone_folder: c:\projects\flax environment: global: MPIR_ROOT_DIR: c:\projects\lib\mpir MPFR_ROOT_DIR: c:\projects\lib\mpfr LLVM_ROOT_DIR: c:\projects\lib\llvm LIBFFI_ROOT_DIR: c:\projects\lib\libffi cache: - c:\projects\lib -> appveyor.yml install: # Set up the build environment - cmd: call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 # download our deps. - ps: "[Net.ServicePointManager]::SecurityProtocol = 'Ssl3, Tls, Tls11, Tls12'" - ps: >- If (!(Test-Path c:\projects\lib -PathType Container)) { Invoke-WebRequest 'https://github.com/flax-lang/flax/releases/download/win-build-deps/libraries.zip' -OutFile 'c:\projects\libs.zip' 7z x -y -oc:\projects\lib c:\projects\libs.zip } # Download ninja - cmd: mkdir C:\ninja-build - ps: (new-object net.webclient).DownloadFile('https://github.com/mesonbuild/cidata/raw/master/ninja.exe', 'C:\ninja-build\ninja.exe') - cmd: set PYTHON_ROOT=C:\python37-x64 # Add neccessary paths to PATH variable - cmd: set PATH=%cd%;C:\ninja-build;%PYTHON_ROOT%;%PYTHON_ROOT%\Scripts;%PATH% # Install meson - cmd: pip install meson build_script: - ps: meson --buildtype=release build/meson-rel - ps: ninja -C build/meson-rel test_script: - ps: cd c:\projects\flax - ps: New-Item -Force -Path build\sysroot\usr\local\lib\flaxlibs -ItemType Directory - ps: Copy-Item -Recurse -Force libs\* build\sysroot\usr\local\lib\flaxlibs\ - ps: build\meson-rel\flaxc.exe -sysroot build\sysroot --ffi-escape -run -backend llvm build\tester.flx - ps: build\meson-rel\flaxc.exe -sysroot build\sysroot --ffi-escape -run -backend interp build\tester.flx - ps: build\meson-rel\flaxc.exe -sysroot build\sysroot --ffi-escape build\tester.flx - ps: .\tester.exe after_test: - cmd: 7z a windows-x64.zip %APPVEYOR_BUILD_FOLDER%\build\meson-rel\flaxc.exe - cmd: 7z a windows-x64.zip %APPVEYOR_BUILD_FOLDER%\build\sysroot\usr\local\lib - cmd: 7z rn windows-x64.zip flaxc.exe sysroot\usr\local\bin\flaxc.exe - cmd: 7z rn windows-x64.zip lib sysroot\usr\local\lib artifacts: - path: windows-x64.zip deploy: - provider: GitHub description: '' artifact: windows-x64.zip auth_token: secure: Sk3O32lE4SgtirIRqI2PWP2tkfCg2Iurz+eFrLN7C9s/nIUCDbxV0T5hjjZqMIw5 on: APPVEYOR_REPO_TAG: true ================================================ FILE: build/a.flx ================================================ // a.flx // Copyright (c) 2020, zhiayang // Licensed under the Apache License Version 2.0. // import libc as _ export a import libc import std::io as _ // import b // import d @entry fn main() { print("uwu\n") } ================================================ FILE: build/b.flx ================================================ // b.flx // Copyright (c) 2020, zhiayang // Licensed under the Apache License Version 2.0. export a import libc ================================================ FILE: build/c.flx ================================================ // ultratiny.flx // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. export ultratiny // import libc as _ import a @entry fn main() { // printf("q = %d\n", 37) } ================================================ FILE: build/d.flx ================================================ // d.flx // Copyright (c) 2020, zhiayang // Licensed under the Apache License Version 2.0. export a import libc ================================================ FILE: build/generate_test.py ================================================ #!/usr/bin/env python3 # taken from github.com/pervognesn/bitwise/ion/generate_test.py import sys def gen_test(reps): template = """ let names(?) = [ "max", "ollie", "coco", "piper", "tim", "bill", "alex", "ron", "isaac", "jim" ] class Animal(?) { init(w: f64) { // printf("make animal w = %f\\n", w) weight = w name = names(?)[rand() % names(?).length] } virtual fn makeNoise() { printf("some generic sound\\n") } var name: str var weight: f64 var cute: bool = true } class Dog(?) : Animal(?) { init() : super(w: 300) { // printf("make dog (w = %f)\\n", weight) } override fn makeNoise() { printf("bark bark (%f)\\n", weight) } virtual fn wag() { printf("wagging tail of length %d\\n", tail) } var tail: int = 37 } class Dalmation(?) : Dog(?) { init() : super() { printf("make dalmation\\n") } override fn wag() { printf("dalmation wags %d\\n", tail) } var numSpots: int } class LinkedList(?) { struct Node { var data: T var prev: &Node var next: &Node } var head: &Node var tail: &Node var count: int init() { } mut fn insert(thing: T) { var nn = alloc mut Node (data: thing, prev: null, next: null) if head == null { head = nn; tail = nn } else { var ot = tail as mut tail = nn nn.prev = ot ot.next = nn } count += 1 } static fn hello() -> T { printf("hi\\n"); return 10 } } fn stuff(?)() { do { // don't question. srand(284811) // fn test() -> f64 { printf("hi\\n"); return 31.51 } let dogs = alloc &Dog(?) [5] { if i % 2 == 1 { it = alloc Dalmation(?) } else { it = alloc Dog(?) } } for dog, i in dogs { printf("%d: %s - ", i, dog.name) dog.wag() } } do { var list: LinkedList(?)! list.insert(10) list.insert(20) list.insert(30) list.insert(40) var head = list.head while(head) { printf("%d\\n", head.data) head = head.next } } } fn genericstuff(?)() { do { fn gincr(x: A) -> A => x + 1 fn apply(x: B, f: fn(B) -> C) -> C => f(x) fn mapstupid(arr: [D:], f: fn(D) -> E, fa: fn(D, fn(D) -> E) -> F) -> [F] { var i = 0 var ret: [F] while i < arr.length { ret.append(fa(arr[i], f)) i += 1 } return ret } printf("set 4:") let new = mapstupid([ 5, 6, 7, 8, 9 ], gincr, apply) for it in new { printf(" %d", it) } printf("\\n") } do { fn map2(arr: [(T, K):], f: fn(T, K) -> R) -> [R] { var i = 0 var ret: [R] while i < arr.length { ret.append(f(arr[i].0, arr[i].1)) i += 1 } return ret } fn add2(x: A, y: B) -> A => x + y printf("set 5:") let new = map2([ (2, 2), (4, 4), (6, 6), (8, 8), (10, 10) ], add2) for it in new { printf(" %d", it) } printf("\\nset (?) done\\n\\n") } } """ outfile = open("build/massive.flx", "wt") outfile.write("export massive\n") outfile.write("import libc as _\n") outfile.write("ffi fn srand(s: i32)\n") outfile.write("ffi fn rand() -> i32\n") # dupes = range(128 * 48) dupes = range(reps) for i in dupes: outfile.write(template.replace("(?)", str(i)) + "\n") outfile.write("@entry fn main() -> i32 {\n") for i in dupes: outfile.write("\tstuff(?)()\n".replace("(?)", str(i))) outfile.write("\tgenericstuff(?)()\n".replace("(?)", str(i))) outfile.write("\treturn 0\n}\n") outfile.close() if __name__ == '__main__': globals()[sys.argv[1]](int(sys.argv[2])) ================================================ FILE: build/gltest.flx ================================================ // gltest.flx // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. // import Foundation import "OpenGL/GL.flx" import "SDL2/SDL.flx" as _ import libc as _ ffi fn rand() -> i32 fn frand(a: f64, b: f64) -> f64 { let r = (rand() as f64) / 2147483647.0 let diff = b - a let x = r * diff return a + x } ffi fn log(a: f64) -> f64 ffi fn sin(a: f64) -> f64 ffi fn fabs(a: f64) -> f64 ffi fn fmin(a: f64, b: f64) -> f64 ffi fn fmax(a: f64, b: f64) -> f64 ffi fn sqrt(a: f64) -> f64 fn clamp(x: f64, lower: f64, upper: f64) -> f64 { return fmin(upper, fmax(x, lower)) } public fn main(argc: i32, argv: &&i8) -> int { SDL_Init(INIT_EVERYTHING) let mw = SDL_CreateWindow("test", 805240832, 805240832, 640, 480, 2) if mw == null { printf("omg no\n") } else { printf("window init: %p\n", mw) } let glc = SDL_GL_CreateContext(mw) SDL_GL_SetAttribute(GL_MULTISAMPLEBUFFERS, 1) SDL_GL_SetAttribute(GL_MULTISAMPLESAMPLES, 2) GL::glClearColor(0, 0, 0, 0) GL::glMatrixMode(GL::GL::PROJECTION) GL::glLoadIdentity() GL::gluPerspective(45.0, (640.0 / 480.0), 0.1, 100.0) GL::glMatrixMode(GL::GL::MODELVIEW) GL::glLoadIdentity() GL::glEnableClientState(GL::GL::VERTEX_ARRAY) GL::glEnableClientState(GL::GL::TEXTURE_COORD_ARRAY) GL::glEnableClientState(GL::GL::COLOR_ARRAY) GL::glEnableClientState(GL::GL::NORMAL_ARRAY) GL::glEnable(GL::GL::MULTISAMPLE) GL::glEnable(GL::GL::DEPTH_TEST) GL::glDepthFunc(GL::GL::LESS) GL::glBlendColor(1.0, 1.0, 1.0, 1.0) var rx: f64 = 0 var ry: f64 = 0 var rz: f64 = 0 let vertices = [ 0.0, -0.525731, 0.850651, 0.850651, 0.0, 0.525731, 0.850651, 0.0, -0.525731, -0.850651, 0.0, -0.525731, -0.850651, 0.0, 0.525731, -0.525731, 0.850651, 0.0, 0.525731, 0.850651, 0.0, 0.525731, -0.850651, 0.0, -0.525731, -0.850651, 0.0, 0.0, -0.525731, -0.850651, 0.0, 0.525731, -0.850651, 0.0, 0.525731, 0.850651 ] // var colours: f64[36] var colours = alloc f64[48] defer free colours var i = 0 while i < 48 { colours[i + 0] = frand(0.3, 0.9) colours[i + 1] = frand(0.3, 0.9) colours[i + 2] = frand(0.3, 0.9) colours[i + 3] = 1.0 i += 4 } let indices: [u8: 60] = [ 1, 2, 6, 1, 7, 2, 3, 4, 5, 4, 3, 8, 6, 5, 11, 5, 6, 10, 9, 10, 2, 10, 9, 3, 7, 8, 9, 8, 7, 0, 11, 0, 1, 0, 11, 4, 6, 2, 10, 1, 6, 11, 3, 5, 10, 5, 4, 11, 2, 7, 9, 7, 1, 0, 3, 9, 8, 4, 8, 0 ] let normals = [ 0.000000, -0.417775, 0.675974, 0.675973, 0.000000, 0.417775, 0.675973, -0.000000, -0.417775, -0.675973, 0.000000, -0.417775, -0.675973, -0.000000, 0.417775, -0.417775, 0.675974, 0.000000, 0.417775, 0.675973, -0.000000, 0.417775, -0.675974, 0.000000, -0.417775, -0.675974, 0.000000, 0.000000, -0.417775, -0.675973, 0.000000, 0.417775, -0.675974, 0.000000, 0.417775, 0.675973 ] var speed = 1.0 var scale = 1.0 var run = true var srx = 0.0 var sry = 0.0 var srz = 0.0 let stderr = fdopen(2, "a") while run { GL::glClear(GL::GL::COLOR_BUFFER_BIT | GL::GL::DEPTH_BUFFER_BIT) GL::glClearColor(0.109, 0.109, 0.109, 1.0) GL::glTranslated(0.0, 0.0, -5.0) GL::glRotated(rx, frand(0, 1), 0, 0) GL::glRotated(ry, 0, frand(0, 1), 0) GL::glRotated(rz, 0, 0, frand(0, 1)) GL::glVertexPointer(3, GL::GL::DOUBLE, 0, vertices.ptr as &void) GL::glColorPointer(4, GL::GL::DOUBLE, 0, colours.ptr as &void) GL::glNormalPointer(GL::GL::DOUBLE, 0, normals.ptr as &void) GL::glDrawElements(GL::GL::TRIANGLES, 60, GL::GL::UNSIGNED_BYTE, indices as &void) GL::glLoadIdentity() SDL_GL_SwapWindow(mw) usleep((1 * 1000) as u32) rx += srx * speed ry += sry * speed rz += srz * speed var e: Event while SDL_PollEvent(&e) == 1 { if e.type == EventType::Quit { printf("\nexiting\n") run = false } else if e.type == EventType::KeyUp { if (&e as &SDL.KeyboardEvent).keysym.sym == SDL.Key.R { srx = frand(-2.5, 2.5) sry = frand(-2.5, 2.5) srz = frand(-2.5, 2.5) } else if (&e as &SDL.KeyboardEvent).keysym.sym == SDL.Key.F { rx = 0 ry = 0 rz = 0 srx = 0 sry = 0 srz = 0 speed = 1.0 glLoadIdentity() } } else if e.type == SDL.EventType.KeyDown { let ke = *(&e as &SDL.KeyboardEvent) if ke.keysym.sym == SDL.Key.Space { srx *= 0.9 sry *= 0.9 srz *= 0.9 } else if ke.keysym.sym == SDL.Key.C { scale -= 0.5 } else if ke.keysym.sym == SDL.Key.V { scale += 0.5 } else if ke.keysym.sym == SDL.Key.X { speed += scale } else if ke.keysym.sym == SDL.Key.Z { speed -= scale } else if ke.keysym.sym == SDL.Key.D { sry -= scale } else if ke.keysym.sym == SDL.Key.A { sry += scale } else if ke.keysym.sym == SDL.Key.Q { srz -= scale } else if ke.keysym.sym == SDL.Key.E { srz += scale } else if ke.keysym.sym == SDL.Key.W { srx -= scale } else if ke.keysym.sym == SDL.Key.S { srx += scale } fprintf(stderr, " \r> %.2lf / %.2lf : %.2lf, %.2lf, %.2lf\r", speed, scale, srx, sry, srz) fflush(stderr) } } /* todo: enums suck */ } return 0 } ================================================ FILE: build/old/raii_poc.flx ================================================ // raii_poc.flx // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. export ultratiny import libc as _ import "tests/scopes.flx" class Foo { init(x: int) { printf("* create foo %d\n", x) this.rc = alloc mut int *this.rc = 1 this.v = x } copy(from: &self) { this.v = from.v; this.rc = from.rc; *this.rc += 1; printf("* copy foo %d/rc: %d\n", this.v, *this.rc) } move(from: &mut self) { this.v = from.v; this.rc = from.rc; from.rc = null; printf("* move foo %d/rc: %d\n", this.v, *this.rc) } deinit { if(this.rc) => *this.rc -= 1; printf("* delete foo %d/rc: %d\n", this.v, *this.rc) } var rc: &mut int var v: int } fn bar() -> Foo { return Foo(x: 7) } fn con(x: Foo) { printf("\nconsumed %d, rc: %d\n\n", x.v, *x.rc) } @entry fn main() { let y = bar() printf("\ny.value = %d, rc: %d\n\n", y.v, *y.rc) let x = Foo(x: 13) printf("\nx.value = %d, rc: %d\n\n", x.v, *x.rc) con(x) // test_scopes::doScopeTest("__llvm_jit__build/test") } /* ! let x = alloc int { it = ... } fails!! todo to cleanup semantics: 1. copy and move constructors must call a base class constructor if there is not default one 2. allow omitting the explicit call if the base class has a no-arg constructor (to prevent init() : super() { ... }) 3. check if constructing stuff in conditionals will wrongly destruct them! todo for implementing destructors properly: 2. only classes can contain other classes! (ANY notwithstanding) 3. similar to how class constructors call the superclass constructors, we need to call base destructors also! 4. virtual destructors! need to add it to the vtable!!!!! */ ================================================ FILE: build/run-test.ps1 ================================================ # hmm Param ( [string] $buildType, [string] $theProgram, [Parameter(ValueFromRemainingArguments=$true)] [string[]]$extraArgs ) robocopy "libs" "build\sysroot\usr\local\lib\flaxlibs" /mir /nfl /ndl /njh /njs /nc /ns /np if($buildType -eq "release") { $buildDir = "build\meson-rel" } if($buildType -eq "debug") { $buildDir = "build\meson-dbg" } if($buildType -eq "debugopt") { $buildDir = "build\meson-reldbg" } ninja -C $buildDir if($?) { # cls & $buildDir\flaxc.exe -Ox -sysroot build\sysroot -run "build\$theProgram.flx" --ffi-escape $extraArgs } if($buildType -eq "release") { copy "$buildDir\flaxc.exe" build\sysroot\usr\local\bin\ } ================================================ FILE: build/speed-test.py ================================================ #!/usr/bin/env python3 import re import os import subprocess import generate_test import prettytable from prettytable import PrettyTable tab = PrettyTable([ "reps", "firs", "total", "lexer", "parser", "typecheck", "codegen" ]) tab.set_style(prettytable.PLAIN_COLUMNS) tab.align = "l" counts = range(32, 1025, 32) # counts = range(32, 64, 32) plots = open("build/plots.txt", "wt") for i in counts: generate_test.gen_test(i) if os.name == "nt": flaxc_path = "build/meson-rel/flaxc.exe" else: flaxc_path = "build/sysroot/usr/local/bin/flaxc" output = subprocess.run([ flaxc_path, "-sysroot", "build/sysroot", "-run", "-backend", "none", "build/massive.flx" ], capture_output = True, text = True).stdout # rex = re.findall(r"compile took (\d+\.\d+) \(lexer: (\d+\.\d+), parser: (\d+\.\d+), typecheck: (\d+\.\d+), codegen (\d+\.\d+)\) ms(.+)", # output) rex = re.compile(r"compile took (\d+\.\d+) \(lexer: (\d+\.\d+), parser: (\d+\.\d+), typecheck: (\d+\.\d+), codegen: (\d+\.\d+)\) ms.*\n(\d+) FIR values generated") m = rex.search(output) t_compile = m.group(1) t_lexer = m.group(2) t_parser = m.group(3) t_typecheck = m.group(4) t_codegen = m.group(5) n_fvals = m.group(6) n_lines = 0 with open("build/massive.flx", "r") as f: for k, l in enumerate(f): pass n_lines = k + 1 f.close() tab.add_row([ n_lines, n_fvals, t_compile, t_lexer, t_parser, t_typecheck, t_codegen ]) print(n_lines, n_fvals, t_compile, t_lexer, t_parser, t_typecheck, t_codegen) plots.write(str(tab)) plots.close() ================================================ FILE: build/supertiny.flx ================================================ // supertiny.flx // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. export supertiny import std::io import libc as _ // import std::io // import std::map import std::opt @raw union ipv4 { _: struct { _: @raw union { bytes2: [u8: 4] raw3: u32 } } _: struct { bytes: [u8: 4] } _: struct { raw2: u32 } raw: u32 } struct foo { x: int } let glob = "foozle"[2:] let glob2 = string("lmao") @entry fn main() { // do { // var addr: ipv4 // addr.raw3 = 0xff01a8c0; // printf("%d.%d.%d.%d\n", addr.bytes[0], addr.bytes[1], addr.bytes[2], addr.bytes[3]); // } do { var x: int var y: int (x, y) = (30, 40) (x, y) = (y, x) printf("%d, %d\n", x, y) } do { printf("%s\n", glob) } // fn foo(a: T) -> T // { // return a // } // do { // // let q = foo(x: 10) // printf("hello, world!\n") // let q = foo!(10) // } // fn qux() -> int => 30 // let x = std::opt::some!(10) // let f = foo!(3) // let q = qux!() /* do { var x: @raw union { bar: f64 foo: i64 } x.bar = 3.14159 printf("x = %.2lf\n", x.bar) printf("x = %d\n", x.foo) } */ } /* import std::opt import std::map var map: std::map! map.insert(3, "foo") let r = map.search(3) libc::printf("map[3] = %s\n", map.search(3) as std::opt::some) let res = map.remove(3) libc::printf("map[3]: res = %d, is_none = %d\n", res, map.search(3) is std::opt::none) */ /* class X { init(c: int) { this.data = c } var data: int } class Y : X { init(c: int) : super(c: c + 30) { } } class Z : Y { init(c: int) : super(c: c - 90) { } } class A { init() { } virtual fn foo(a: &Y) -> &Y { std::io::println("A::foo()") return alloc Y(c: 471) } } class B : A { init() : super() { } override fn foo(a: &X) -> &Z { std::io::println("B::foo()") return alloc Z(c: 748) } } */ /* ! important stuff to fix ! { 2. splatting tuples into a generic function *will not work* 3. pass the overall location to the polymorph solver. 5. for optional arguments on virtual functions, we need to reach a decision --- do we ban it entirely, or follow what c++ does, which is to use the default values specified on the static type of the pointer? note: we are definitely *not* going to handle it at runtime. 6. see the error message when we pass a [T1:] to a [T2:...] without splatting; we should probably give a better diagnostic, and eg. recommend splatting it, if the internal types match (ie. T1 == T2). at the very least, the current message complains about casting [T1:] to T2, which isn't really correct. } TODO for the immediate time frame (that keeps getting longer and where the real work always gets postponed) 7. move long error messages on spans nearer to the left margin when there's only one span in the error. 9. fix errors (in general?) { a. the generic solver should basically return only a Span, ie. a location with text. b. maybe find some way to 'link' two spans together with one message. c. figure out if/how we should split up errors when there are too many spans in one context. - do we duplicate the context? - if not then??? } 16. operator overload errors { something like this: failed to resolve candidate for 'operator == (type_1, type_2)' callsite was here: 'foo == bar' potential candidates: 'operator == (type_1, type_3)' ofc potential candidates should be limited to ones where at least one of the types are similar. } 17. better errors for ref-counting legality { when throwing an error due to having a ref-counted type in unsupported places (like in a raw-union), we should let the compiler show which member made the struct refcounted (because having a RC field in a struct makes that struct RC), since the 'root cause' could be nested very deep in the type hierarchy somewhere. eg. error: reference-counted type 'foo' cannot be a member of a raw-union: 39 | bar: foo note: 'foo' inherits reference-counting from indirectly containing a field with a reference-counted type: 303 | blabla: string note: this is the type hierarchy leading from 'foo' leading to the type in question: (foo <- qux <- some_type_t <- ... <- some_struct <- string) of course it would be nice if we can selectively print more context and omit stuff in the middle, like this: 10 | struct some_struct { ... | ... 391 | blabla: string | something like that. detecting indentation would be a little tricky if we want to correctly indent the '...' that would appear in the struct body. actually having a proper API to set up this kind of error message would be a tough one as well... } 18. figure out how constructors should work with transparent fields { I think it's currently not worth the effort to support initialising transparent fields in constructors; there's way too much stuff that needs to change. some findings: to actually allow it to pass typechecking, we just need to pass the "extended set" of field names to `verifyStructConstructorArguments`, which ought to suffice. problem is, we call that from the polymorph engine as well, and that's something i don't really feel like touching at the moment. ^ as a corollary to that, we also need a way to discover all the transparent fields that are accessible at any point. currently in typecheck/dotop, we currently do an ad-hoc kind of thing, where we search for a particular name that's needed. should be not-that-difficult to get a list of all accessible things, i hope. ^ we might need to duplicate this to work with ast::StructDefn as well, since the polymorph engine also uses the same verifyStructConstructorArguments to instantiate types a-la function calls. we also need some way to actually insert the value into the struct when it's being constructed, which might also get complicated. TL;DR: too complicated, not worth the time currently. } */ ================================================ FILE: build/tester.flx ================================================ // tester.flx // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. export tester import libc import std::io import std::limits import "tests/fizzbuzz.flx" import "tests/recursiveFib.flx" import "tests/slices.flx" import "tests/classes.flx" import "tests/scopes.flx" import "tests/defertest.flx" import "tests/anytest.flx" import "tests/decomposition.flx" import "tests/intlimits.flx" import "tests/generics.flx" import "tests/linkedlist.flx" import "tests/forloops.flx" import "tests/arraytest.flx" import "tests/functions.flx" import "tests/unions.flx" import "tests/using.flx" import "tests/basic.flx" fn runTests() { // fib let fibTitle = " *** FIBONACII SEQUENCE *** \n" let fizzbuzzTitle = " *** FIZZBUZZ *** \n" let intLimitsTitle = " *** PRINTING INT LIMITS *** \n" let scopeTitle = "*** SCOPE RESOLUTION REGRESSION TEST ***\n" let operatorTitle = " *** OPERATOR/TUPLE REGRESSION TEST *** \n" let arrayTitle = " *** ARRAY REGRESSION TEST *** \n" let genericsTitle = " *** GENERICS REGRESSION TEST *** \n" let functionsTitle = " *** FUNCTION REGRESSION TEST *** \n" let classTitle = " *** CLASS REGRESSION TEST *** \n" let deferTitle = " *** DEFER SEMANTICS TEST *** \n" let anyTitle = " *** ANY SEMANTICS TEST *** \n" let slicesTitle = " *** SLICES REGRESSION TEST *** \n" let decomposeTitle = " *** DECOMPOSITION REGRESSION TEST *** \n" let forLoopTitle = " *** FOR LOOP REGRESSION TEST *** \n" let linkedListTitle = " *** LINKED LIST TEST *** \n" let unionsTitle = " *** UNIONS TEST *** \n" let usingTitle = " *** USING TEST *** \n" let miscTitle = " *** MISCELLANEOUS TESTS *** \n" let basicTitle = " *** BASIC TESTS *** \n" let thinLine = "----------------------------------------\n" let endTitle = "============ TESTS COMPLETE ============\n" std::io::print("%%", fibTitle, thinLine) do { var n = 1 while n < 20 { std::io::print("%", test_fib::doRecursiveFib(n)) n += 1 if n != 20 { std::io::print(", ") } } std::io::print("\n\n\n") } // fizzbuzz std::io::print("%%", fizzbuzzTitle, thinLine) test_fizz::doFizzBuzz(15) std::io::print("\n\n\n") // int limits std::io::print("%%", intLimitsTitle, thinLine) test_limits::printIntegerLimits() std::io::print("\n\n\n") // scopes std::io::print("%%", scopeTitle, thinLine) test_scopes::doScopeTest("__llvm_jit__build/test") std::io::print("\n\n\n") // operators and tuples (vectors type, mainly) std::io::print("%%", operatorTitle, thinLine) // doOperatorTupleTest() std::io::print("\n\n\n") // arrays std::io::print("%%", arrayTitle, thinLine) test_arrays::doArrayTest() std::io::print("\n\n\n") // generics std::io::print("%%", genericsTitle, thinLine) test_generics::doGenericsTest() std::io::print("\n\n\n") // classes std::io::print("%%", classTitle, thinLine) test_classes::doClassTest() std::io::print("\n\n\n") // first-class-functions std::io::print("%%", functionsTitle, thinLine) test_functions::doFunctionTest() std::io::print("\n\n\n") // defer semantics std::io::print("%%", deferTitle, thinLine) test_defer::doDeferTest() std::io::print("\n\n\n") // any std::io::print("%%", anyTitle, thinLine) test_any::doAnyTest() std::io::print("\n\n\n") // slices std::io::print("%%", slicesTitle, thinLine) test_slices::doSlicesTest() std::io::print("\n\n\n") // decomposition std::io::print("%%", decomposeTitle, thinLine) test_decomposition::doDecompositionTest() std::io::print("\n\n\n") // for-loops std::io::print("%%", forLoopTitle, thinLine) test_forloops::doForLoopTest() std::io::print("\n\n\n") // linked-list (generics) std::io::print("%%", linkedListTitle, thinLine) test_linkedlist::doLinkedListTest() std::io::print("\n\n\n") // unions (generics) std::io::print("%%", unionsTitle, thinLine) test_unions::doUnionsTest() std::io::print("\n\n\n") // using std::io::print("%%", usingTitle, thinLine) test_using::doUsingTest() std::io::print("\n\n\n") // misc tests std::io::print("%%", miscTitle, thinLine) // miscellaneousTests() std::io::print("\n\n\n") std::io::print("%%", basicTitle, thinLine) test_basic::doBasicTest() std::io::print("\n\n\n") // fin. std::io::print("%\n\n\n\n\n", endTitle) } @entry fn main() -> int { runTests() std::io::print("\n<< done >>\n") return 0 } ================================================ FILE: build/tests/anytest.flx ================================================ // anytest.flx // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. export test_any // import "stdio" as _ import libc as _ var glob: any struct Large { a: i64 b: i64 c: i64 d: i64 e: i64 } public fn doAnyTest() { fn foo(a: any) { if(a is Large) { printf("a = %d\n", (a as Large).a) glob = a } else { printf("not large\n") } } do { var k: any = any(40) k = "foo" printf("k as int = %s\n", k as str) k = 301 printf("k as int = %d\n", k as int) printf("typeid(k): %d\n", typeid(k)) } do { var x: any = Large(10, 20, 30, 40, 50) var k = x as Large k.c = 173 k.a = 631 foo(x) foo(k) foo(401.3) fn bar() -> any => any(10) printf("bar = %d, qux = %d\n", bar() as int, 30) printf("a = %d, b = %d, c = %d/%x, d = %d, e = %d\n", k.a, k.b, k.c, (x as Large).c, k.d, k.e) } } ================================================ FILE: build/tests/arraytest.flx ================================================ // arraytest.flx // Copyright (c) 2014 - 2015, zhiayang // Licensed under the Apache License Version 2.0. export test_arrays import libc public fn doArrayTest() { do { var arr: [[int: 2]: 2] = [ [ 1, 2 ], [ 5, 6 ] ] arr[1][1] = 400 libc::printf("a[0][0]: %d, a[0][1]: %d, a[1][0]: %d, a[1][1]: %d\n", arr[0][0], arr[0][1], arr[1][0], arr[1][1]) var d: [f64: 4] = [ 1.0, 2.0, 4.0, 8.0 ] libc::printf("d[0]: %f, d[1]: %f, d[2]: %f, d[3]: %f\n", d[0], d[1], d[2], d[3]); var arr1: &mut int = @raw alloc mut int [4] arr1[1] = 97 arr1[2] = 43 libc::printf("arr[1] = %d\n", (arr1 + 1)[0]) libc::printf("arr[2] = %d\n", (3 + arr1)[-1]) free arr1 libc::printf("\n\n") // var s = alloc[4][4] string("array of array of strings test") // s[1][2] = "BOO YOU STRING" // libc::printf("s[1][2] = %s, s[1][2].length = %ld\n", s[1][2], s[1][2].length) // free s } libc::printf("\n") dynamicArrays() } fn foldl(arr: [T:], x: T, f: fn(T, T) -> T) -> T { if arr.length == 0 => return x return foldl(arr[1:], f(x, arr[0]), f) } fn foldr(arr: [T:], x: T, f: fn(T, T) -> T) -> T { if arr.length == 0 => return x return f(foldr(arr[:$-1], arr[0], f), x) } fn f(a: int, b: int) -> int { return a * b } fn setup(max: int) -> [int] { var arr: [int] var i = 1 while i <= max { arr.append(i) i += 1 } return arr } fn dynamicArrays() { do { libc::printf("PRE X\n") var x: [string] libc::printf("POST X\n") var y = alloc string [5] var i = 0 x.append(string("aaa") + string("AAA")) x.append(string("BBB") + string("bbb")) x.append(string("ccc") + string("CCC")) x.append(string("DDD") + string("ddd")) x.append(string("eee") + string("EEE")) x += y let k = x var z = k.clone() libc::printf("z.length = %d\n", z.length) z[9] = string("LAST ELEMENT") libc::printf("z <= x: %d\n", z <= x) while i < z.length { libc::printf("z[%ld] = %s // %ld\n", i, z[i], z[i].refcount) i += 1 } libc::printf("z.back() = %s, length = %ld, cap = %ld\n", z[z.length - 1], z.length, z.capacity) libc::printf("x == k ? %d\n", x == k) let fib = setup(5) let sum = foldl(fib, 1, f) libc::printf("sum = %d\n", sum) } } /* MAKE: 110 / 195 SHAKE: 107 / 191 FMODULES: 95 / 166 96 / 167 */ ================================================ FILE: build/tests/basic.flx ================================================ // basic.flx // Copyright (c) 2019, zhiayang, Apache License 2.0. export test_basic import libc as _ import std::io as _ // TODO: reorganise these tests if possible // eg. move them to a more appropriate file? I think some of these might fit. public fn doBasicTest() { // put a default argument here so we can test that. fn print_array(xs: [T:]) { for x in xs => print("% ", x) println() } // test logical operators do { fn t() -> bool { print("T "); return true } fn f() -> bool { print("F "); return false } if t() || f() => println("yes") if t() && f() => println("no") printf("\n\n") } // test tuple assignment do { var (a, b) = (10, 20) println("a = %, b = %", a, b) (b, a) = (a, b) println("swapped: a = %, b = %\n", a, b) } // test assignment & appending do { do { var xs: [str] = [ "foo", "bar" ] xs += "qux" var ys: [i64] = [ 1, 2, 3, 4 ] ys += 5 as i64 print_array(xs) print_array(ys) } println() do { var xs: [str] = [ "foo", "bar" ] xs += [ "pepega", "kekw" ] var ys: [i64] = [ 1, 2, 3, 4 ] ys += [ 5, 6, 7, 8 ] print_array(xs) print_array(ys) } println() do { var s = string("some string") s += "_appendage" var t = string("an underscore: ") t += '_' println("s = %", s) println("t = %", t) } } println() // test + on non-arithmetics do { let a = string("hello ") + "world" println("a = %", a) let b = string("an asterisk: ") + '*' println("b = %\n", b) let c: [int] = [ 2, 3, 5, 7 ] let d: [int] = [ 11, 13, 17, 19 ] print_array(c + d) } println() // test builtin functions on aggregate data types do { var a: [int] = [ 2, 3, 5, 7 ] print("% : ", a.pop()) print_array(a) var b: [int: 3] = [ 1, 4, 9 ] // drop to printf for %p support printf("b.ptr = %p, b.length = %d\n\n", b.ptr, b.length) var s = string("thank you ございました") println("\"%\".count = % (expect 16)\n", s, s.count) var r = 0...10 step 2 for i in r => print("% ", i) println("\nstart: %, end: %, step: %", r.begin, r.end, r.step) var c: any = 30 println("c.typeid = %, c.refcount = %", c.id, c.refcount) enum E: u32 { case ONE = 100 case TWO = 200 } var e = E::TWO println("e.index = %, e.value = %, e.name = %", e.index, e.value, e.name) } println() // other strange things do { struct Foozle { x: fn(int) -> int fn foo() -> int { return x(30) } } fn triple(x: int) -> int => x * 3 let f = Foozle(x: triple) println("f = %", f.foo()) let g = triple println("g(76) = %", g(76)) } println() } // well just a test. #run println("** hello, world!") ================================================ FILE: build/tests/classes.flx ================================================ // classes.flx // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. export test_classes import libc as _ ffi fn srand(s: i32) ffi fn rand() -> i32 let names = [ "max", "ollie", "coco", "piper", "tim", "bill", "alex", "ron", "isaac", "jim" ] class Animal { init(w: f64) { // printf("make animal w = %f\n", w) weight = w name = names[rand() % names.length] } virtual fn makeNoise() { printf("some generic sound\n") } var name: str var weight: f64 var cute: bool = true } class Dog : Animal { init() : super(w: 300) { // printf("make dog (w = %f)\n", weight) } override fn makeNoise() { printf("bark bark (%f)\n", weight) } virtual fn wag() { printf("wagging tail of length %d\n", tail) } var tail: int = 37 } class Dalmation : Dog { init() : super() { printf("make dalmation\n") } override fn wag() { printf("dalmation wags %d\n", tail) } var numSpots: int } public fn doClassTest() { do { // don't question. srand(2848131) let dogs = alloc &Dog [10] { if i % 3 == 1 => it = alloc Dalmation else => it = alloc Dog if i % 2 == 1 => (it as mut).tail = i + 1 * 3 } for dog, i in dogs { printf("%d: %s: \t", i, dog.name) dog.wag() } } } ================================================ FILE: build/tests/decomposition.flx ================================================ // decomposition.flx // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. export test_decomposition import libc as _ public fn doDecompositionTest() { do { printf("\n\n>> tuple decomposition\n") let tup = (10, 20, 30) let (x, &y, _) = tup printf("x = %d, y = %d\n", x, y == null) let (a, (b, c, _, _)) = ("a", (30, 40, 50, 60)) printf("a = '%s', b = %d, c = %d\n", a, b, c) } do { printf("\n>> array decomposition\n") var arr = [ 2, 3, 5, 7, 11, 13, 17 ] var [ a, &b, &c, ... &x ] = arr *(b as mut) = 30 printf("a = %d, b = %d, c = %d, d = %d, e = %d (x.length = %d)\n", a, *b, c == null, x[0], x[1], x.length) do { var arr2: [str] arr2.append("hello") arr2.append("world") arr2.append("bouys") let [ a, ... &b ] = arr2 // can bind directly, if you're that kind of person... let [ ... &c ] = arr2 printf("a = %s, b = %d, c = %d\n", a, b.length, c.length) } do { printf("\n>> string decomposition\n") let longstring = "In the event of unexpected shutdown, all personnel are to evacuate the area immediately.\n\n" let [ a, b, c, ... &chars ] = longstring printf("a = '%c', b = '%c', c = '%c'\n", a, b, c) // this should not, and thankfully, does not, work. // chars[3] = char("$") var k = 0 while k < chars.length { printf("%c", chars[k]) k += 1 } } } } ================================================ FILE: build/tests/defertest.flx ================================================ // defer.flx // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. export test_defer import libc as _ public fn doDeferTest() { bar() } fn foo(x: int) -> int { printf("calling foo %d\n", x) return 2 * x } fn bar() -> int { // numbered by *correct* order of appearance. // defer should execute after the return. foo(1) defer foo(3) return foo(2) } ================================================ FILE: build/tests/fizzbuzz.flx ================================================ // fizzbuzz.flx // Copyright (c) 2014 - 2015, zhiayang // Licensed under the Apache License Version 2.0. export test_fizz import libc public fn doFizzBuzz(num: int) { var i = 0 while i <= num { libc::printf("%02d: ", i) if i % 3 == 0 { libc::printf("Fizz") } if i % 5 == 0 { libc::printf("Buzz") } if i % 5 != 0 && i % 3 != 0 { libc::printf("%d", i) } libc::printf("\n") i += 1 } } ================================================ FILE: build/tests/forloops.flx ================================================ // forloops.flx // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. export test_forloops import libc as _ public fn doForLoopTest() { do { printf("\n>> ranges\n") let r1 = 0 ... 3 let r2 = 0 ..< 1 printf("r1.l = %d, r1.u = %d\n", r1.begin, r1.end) printf("r2.l = %d, r2.u = %d\n\n", r2.begin, r2.end) for i, j in r1 { printf("%d: i = %d\n", j, i) } } do { printf("\n>> for-in array\n") let x = [ (1, "a"), (2, "b"), (3, "c"), (4, "d") ] let fixed: [(int, int): 3] = [ (10, 2), (7, 3), (3, 2) ] for (a, b), i in x { printf("%d: %d / %s\n", i, a, b) } } do { printf("\n>> for-in string\n") for c, i in "woohoo" { printf("%d: '%c', ", i, c) } printf("\n") } } ================================================ FILE: build/tests/functions.flx ================================================ // functions.flx // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. export test_functions import libc as _ fn foo(a: int) { printf("foo: %d\n", a) } fn bar(a: int) { printf("bar: %d\n", a) } fn qux() { ("qux\n") } class SomeClass { init() { } fn foo(a: int) { printf("foo in class: %d\n", a) } static fn bar(a: int) { printf("static bar in class: %d\n", a) } } namespace SomeNS { fn foo(a: int) { printf("foo in namespace: %d\n", a) } class NestedClass { init() { } fn foo(a: int) { printf("foo in nested class: %d\n", a) } static fn bar(a: int) { printf("static bar in nested class: %d\n", a) } // fn mgen(a: T) -> T { printf("method generic: %p // %d\n", self, a) } // static fn smgen(a: T) -> T { printf("static generic: %d\n", a) } } // fn ngen(a: T) -> T { printf("namespace generic: %p // %d\n", a) } } fn gen(a: T) -> T { if(typeid(a) == typeid(int)) => printf("int: %d\n", a) else if(typeid(a) == typeid(f64)) => printf("float: %lf\n", a) return a + 1 } fn et(a: int) { printf(" %d", a) } fn et1(a: int) -> int { printf(" %d", a) return a } class SomeStruct { init() { } var f: fn(&SomeStruct, int) -> int fn fun(a: string) -> int { printf("method: %s\n", a) return 40 } static fn sfn(self: &SomeStruct, a: int) -> int { printf("static: %d\n", a); return a; } } public fn doFunctionTest() { var f = qux f() var g = foo g(10) g = bar g(20) printf("each test:") let arr = (alloc int[4])[:].ptr arr[0] = 11 arr[1] = 22 arr[2] = 33 arr[3] = 44 each(arr, 4, et) printf("\n\nscope test\n") do { g = SomeClass::bar g(10) g = SomeNS::NestedClass::bar g(20) g = SomeNS::foo g(30) } printf("\nmethod test\n") do { var method = SomeClass::foo let sc = SomeClass() method(&sc, 40) var method2 = SomeNS::NestedClass::foo let nc = SomeNS::NestedClass() method2(&nc, 50) } // printf("\ngeneric test\n") // do { // var gf: [(int) -> int] = gen // var gff: [(f64) -> f64] = gen // gf(100) // gff(3.1415926536) // // gf = SomeNS.ngen // gf(200) // // reassignment // printf("\nclass test\n") // do { // var gf2: [(int) -> int] = et1 // printf("et:"); gf2(300); printf("\n") // gf2 = gen // gf2(400) // var s = SomeStruct() // let gf3 = SomeStruct.sfn // gf3(&s, 500) // s.f = gf3 // let gf4 = s.f // gf4(&s, 600) // printf("\ngeneric member test\n") // let gf5: [(int) -> int] = SomeNS.NestedClass.smgen // gf5(10) // var gf6: [(SomeNS.NestedClass*, int) -> int] // gf6 = SomeNS.NestedClass.mgen // let nc = SomeNS.NestedClass() // gf6(&nc, 10) // printf("\ndirect field calling\n") // let res1 = s.f(&s, 10) // } // } } fn each(arr: &int, length: int, f: fn(int) -> void) { var i = 0 while i < length { f(arr[i]) i += 1 } } ================================================ FILE: build/tests/generics.flx ================================================ // generics.flx // Copyright (c) 2014 - 2015, zhiayang // Licensed under the Apache License Version 2.0. export test_generics import libc as _ public fn doGenericsTest() { // some normal FP stuff fn map(arr: [T:], fun: fn(T) -> U) -> [U] { var ret: [U] for it in arr => ret.append(fun(it)) return ret } do { printf("set 1:") fn twice(a: K) -> K => a * 2 let new = map(fun: twice, arr: [ 1, 2, 3, 4, 5 ]) for it in new { printf(" %d", it) } printf("\n") } do { printf("set 2:") fn twice(a: str) -> string => string(a) + string(a) let new = map([ "a", "b", "c", "d", "e" ], twice) for it in new => printf(" %s", it) printf("\n") } do { printf("set 3:") fn square(a: T) -> U => (a * a) let new: [f64] = map([ 7.3, 8.7, 9.1, 10.4, 11.6 ], square) for it in new { printf(" %.2f", it) } printf("\n") } do { fn gincr(x: A) -> A => x + 1 fn apply(x: B, f: fn(B) -> C) -> C => f(x) fn mapstupid(arr: [D:], f: fn(D) -> E, fa: fn(D, fn(D) -> E) -> F) -> [F] { var i = 0 var ret: [F] while i < arr.length { ret.append(fa(arr[i], f)) i += 1 } return ret } printf("set 4:") let new = mapstupid([ 5, 6, 7, 8, 9 ], gincr, apply) for it in new { printf(" %d", it) } printf("\n") } do { fn map2(arr: [(T, K):], f: fn(T, K) -> R) -> [R] { var i = 0 var ret: [R] while i < arr.length { ret.append(f(arr[i].0, arr[i].1)) i += 1 } return ret } fn add2(x: A, y: B) -> A => x + y printf("set 5:") let new = map2([ (2, 2), (4, 4), (6, 6), (8, 8), (10, 10) ], add2) for it in new { printf(" %d", it) } printf("\n") } do { fn prints(m: T, a: [U: ...]) { for x in a => printf(" %.2d", m * x) } printf("set 6:") let xs = [ 1, 2, 3, 4, 5 ] prints(3, ...xs) printf("\n") } } ================================================ FILE: build/tests/intlimits.flx ================================================ // intlimits.flx // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. export test_limits import libc import std::limits public fn printIntegerLimits() { libc::printf(" i8::min = %hhd\t\t\t i8::max = %hhd\n", std::limits::int8::min, std::limits::int8::max); libc::printf("i16::min = %hd\t\t\ti16::max = %hd\n", std::limits::int16::min, std::limits::int16::max); libc::printf("i32::min = %d\t\t\ti32::max = %d\n", std::limits::int32::min, std::limits::int32::max); libc::printf("i64::min = %lld\ti64::max = %lld\n", std::limits::int64::min, std::limits::int64::max); libc::printf("\n") libc::printf(" u8::min = %hhu\t\t\t\t u8::max = %hhu\n", std::limits::uint8::min, std::limits::uint8::max); libc::printf("u16::min = %hu\t\t\t\tu16::max = %hu\n", std::limits::uint16::min, std::limits::uint16::max); libc::printf("u32::min = %u\t\t\t\tu32::max = %u\n", std::limits::uint32::min, std::limits::uint32::max); libc::printf("u64::min = %llu\t\t\t\tu64::max = %llu\n", std::limits::uint64::min, std::limits::uint64::max); } ================================================ FILE: build/tests/linkedlist.flx ================================================ // linkedlist.flx // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. export test_linkedlist import libc as _ class LinkedList { struct Node { prev: &Node next: &Node data: T } var head: &Node var tail: &Node var count: int init(data: T) { printf("called init\n") } mut fn insert(thing: T) { var nn = alloc mut Node (data: thing, prev: null, next: null) if head == null { head = nn; tail = nn } else { var ot = tail as mut tail = nn nn.prev = ot ot.next = nn } count += 1 } static fn hello() { printf("hi\n"); } } public fn doLinkedListTest() { do { var list = LinkedList(data: 41) LinkedList!::hello() var list2 = LinkedList(data: "foo") list2.insert("hello") list2.insert("world") list.insert(10) list.insert(20) list.insert(30) list.insert(40) do { var head = list.head while(head) { printf("%d\n", head.data) head = head.next } } do { var head = list2.head while(head) { printf("%s\n", head.data) head = head.next } } } } ================================================ FILE: build/tests/misc.flx ================================================ // misc.flx // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. class TestingClass { init(x: int) { self.thing = x } var thing: int } extension TestingClass : StringConvertible, Equatable { fn toString() -> string { "hello" } operator == (a: TestingClass) -> bool { return self.thing == a.thing } } fn cts(thing: T) -> string { return thing.toString() } fn pt(a: T, b: &T) -> T { return a } fn vt(b: T[...]) { var i = 0 while i < b.length { printf("%d\n", b[i]) i += 1 } } fn vt2(a: T, b: int[...]) { // do something. variadicTest(a, b) } @nomangle fn mtest(k: int, g: int) { printf("(%d, %d)\n", k, g) let x = TestingClass(10) let y = TestingClass(20) let g = 10 pt(10, &g) vt(10, 30, 40, 50, 60) vt2("hi", 1, 2, 3, 4) printf("%d, (%s, %s, %s, %s)\n", x == y, cts(k), cts(x), cts(g), cts(y)) } // although it would be possible to move the slipshod array system into a generic Array<> thing, once it's implemented // sidenote: oh look, it works for arbitrary types. // sometimes, i'm impressed by the things i've implemented. // i think this form of varargs should *stay*, since it's basically a compiler primitive. // once we have an Array<> type, then it'd be as simple as having the Array class define an initialiser with T[...], // since we can forward LLVarArrays effortlessly. then it's as easy as let arr = Array(b), and you can have all the Array<> class // niceties with varargs, without compromising freestanding functionality. // imho it's not worth it to have the compiler do the same thing as with String, because 1. String is not generic, and 2. varargs isn't // a "core" language feature, so to speak. public fn variadicTest(a: string, b: int[...]) { printf("%s: [", a) var i = 0 while i < b.length { printf("%d", b[i]) i += 1 if i != b.length { printf(", ") } } printf("]\n") } extension string { // static fn withRaw(r: int8*) -> string // { // var s: string // let len = strlen(r) // s.raw = malloc(len + 8 + 1) // } } public fn miscellaneousTests() { mtest(10, 41) do { var bar = (10, 20) var foo: &&(&&(&&(float, float)[10])[3]) } do { var g = "439" let k = g.toInteger() printf("%s, %d\n", g, k) } do { printf("'4' is digit: %d\n", char("5").isDigit()) } do { struct winsize { var row: u16 var col: u16 var xpixel: u16 var ypixel: u16 } var ws: winsize ioctl(1, 1074295912 as u64, &ws) printf("terminal size: %hdx%hd (chars), %hdx%hd (pixels)\n", ws.col, ws.row, ws.xpixel, ws.ypixel) } do { fn test() -> string { return "hello!" } let s = string("hello") string("hello").raw printf("test = %p %d\n", test().raw, i64(10)) } do { if let k = 30; k > 27 { printf("(if-let) k > 27\n") } } do { enum SomeEnum { case Up case Down case Left case Right } struct Foop { var x: int } class Barf { static var y: int = 40 static var fkr: int { get { 30 } } fn foo() -> f64 { 43.1 } } let e = SomeEnum.Down let f = Foop(10) let barf = Barf() let fo = barf.foo printf("f.x = %d, b.c = %d, fo = %d\n", f.x, 3, Barf.y) let tup = ("a", (30, 40, 50, 60)) let k = tup.1.1 printf("k = %d\n", k) let s = "some string \ broken over \ multiple lines" printf("s = %s\n", s) printf("%d, %.7lf\n", k, +3.000141); } do { fn foo(a: T[], b: T) { } fn bar(a: T, b: T[]) { } bar(10, [ ]) foo([ ], 20) var z: int[:] struct Test { var a: int var b: int } let ta = Test(10, 10) let tb = Test(10, 10) printf("> %d / %d / %d <\n", sizeof(Test), sizeof(ta), sizeof(&ta)) printf("ta == tb: %d\n", ta == tb) } variadicTest("ints", 10, 20, 30, 40, 50, 60) } ================================================ FILE: build/tests/operators.flx ================================================ // operators.flx // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. import Math import Foundation class CPTest { var readwrite: int { get { printf("READ\n"); return 31 } set { printf("WRITE: %d\n", value) } } } public fn doOperatorTupleTest() { do { let g: i8 = 100 printf("g is: %d\n", g) } do { let m = (fa(), fb()) printf("m is [(%f, %f, %f), (%f, %f, %f)]\n", m.0.x, m.0.y, m.0.z, m.1.x, m.1.y, m.1.z) let dot = m.0 • m.1 printf("dot = %f\n", dot); let v1 = Math.Vector3(1.0, 2.0, 4.0) let v2 = Math.Vector3(3.0, 6.0, 9.0) var v = v1 + v2 printf("v: (%f, %f, %f)\n", v.x, v.y, v.z) v += v1 v = v1 + v2 + v1 let vv = 3 * v printf("v: (%f, %f, %f)\n", v.x, v.y, v.z) printf("vv: (%f, %f, %f)\n", vv.x, vv.y, vv.z) let cross = m.0 ⨯ m.1 printf("cross = (%f, %f, %f)\n", cross.x, cross.y, cross.z) let crossn = m.1 ⨯ m.0 printf("crossn = (%f, %f, %f)\n", crossn.x, crossn.y, crossn.z) } do { // var args = alloc[10] Any // args[0] = "HELLO" // #(args + 1) = 40 // args[2] = "GOODBYE" } do { let v1 = Math.Vector2(1.0, 4.0) let v2 = Math.Vector2(3.0, 7.0) let vr = v1 ⨯ v2 printf("(%.2f), vr = %.2f\n", v1 • v2, vr) var lol: string = "HELLO" printf("%c\n", lol[1]) printf("lol[2]: %c // %s\n", lol[1], lol) } } fn fa() -> Math.Vector3 { var ret: Math.Vector3 ret.x = 1 ret.y = 2 ret.z = 3 return ret } fn fb() -> Math.Vector3 { var ret: Math.Vector3 ret.x = 4 ret.y = 5 ret.z = 6 return ret } ================================================ FILE: build/tests/recursiveFib.flx ================================================ // recursiveFib.flx // Copyright (c) 2014 - 2015, zhiayang // Licensed under the Apache License Version 2.0. export test_fib fn doRecursiveFib(n: int, v: int, prev: int) -> int { if n == 0 { return prev } if n == 1 { return v } return doRecursiveFib(n - 1, v + prev, v) } public fn doRecursiveFib(n: int) -> int { return doRecursiveFib(n, 1, 0) } ================================================ FILE: build/tests/scopes.flx ================================================ // scopes.flx // Copyright (c) 2014 - 2015, zhiayang // Licensed under the Apache License Version 2.0. export test_scopes import libc as _ import std::math @operator[prefix, 900, √] operator prefix √ (x: f64) -> f64 { return math::sqrt(x) } class Orr { init() { } static var Another = 76 var bar: int = 371 } class Something { init() { } fn somefoo() -> Orr => Orr() static var Or: Orr var oor: int = 400 class Inside { init() { } fn insideFoo() -> int => 10 static fn staticInside() -> int => 23 static var Another = 511 } enum InsideEnum : i64 { case None case Single case Double case Triple case Quadruple case Quintuple case Hextuple } } enum OutsideEnum : i64 { case Zero case One case Two case Three case Four } enum StrongEnum : i64 { case Red case Green case Blue } class Sheep { init() { } var thing: int = 43 var foo: Something static var afoo: Something } namespace n1 { namespace n2 { var m: Sheep var tup: (str, int) fn nest() -> (str, int) { printf("nested\n"); return ("TUPLE ONE", 591) } class DeepClass { init() { } class DeeperClass { init() { } static fn deepStatic() -> int => 23 } } } } public fn doScopeTest(argv: str) { let p = 64.4 ÷ 4.1 let m = √(41.5) let mmx = Something::Inside::Another let another = 4 let foo = Something() let mm = foo.somefoo().bar let gg = (4, 100.39) printf("gg.0: %d, gg.1: %.2f\n", (4, 50).0, gg.1) printf("[%d]\n", foo.oor) printf("p: %f, g: %d, m: %d, %.14f\n\n", p, another, mmx, math::π) let x1: int = OutsideEnum::Three as int let x2: int = Something::InsideEnum::Quadruple as int let x3 = n1::n2::DeepClass::DeeperClass() printf("x1: %d, x2: %d, x3: %d\n", x1, x2, n1::n2::DeepClass::DeeperClass::deepStatic()) n1::n2::m.foo.oor = 968 printf("oor = %d\n", n1::n2::m.foo.oor) let t1 = n1::n2::m.foo.somefoo().bar let t2 = n1::n2::nest().0.length n1::n2::tup.0 = "HELLO, WORLD!" //string("HELLO, WORLD") + "!" printf("tup: %s\n", n1::n2::tup.0) printf("t1 = %d, t2 = %d\n", t1, t2) printf("afoo: %d\n", Sheep::afoo.somefoo().bar) } ================================================ FILE: build/tests/slices.flx ================================================ // slices.flx // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. export test_slices import libc public fn doSlicesTest() { do { var arr = [ 2, 3, 5, 7, 11, 13, 17 ] let slice = arr[:] libc::printf("-- %d, %d, %d, %d, %d, %d, %d --\n", slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6]) let s = "Hello, world!" libc::printf("original: %s\nslice: %.*s\n", s, s[3:10].length, s[3:10]) } } @entry fn main() { doSlicesTest() } ================================================ FILE: build/tests/unions.flx ================================================ // unions.flx // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. export test_unions import libc as _ union option { some: T none } @raw union ipv4 { _: struct { _: @raw union { bytes2: [u8: 4] raw3: u32 } } _: struct { bytes: [u8: 4] } _: struct { raw2: u32 } raw: u32 } public fn doUnionsTest() { do { let x = option::some("foobar") let y = option::some(456) printf("x = %s, y = %d\n", x as option!::some, y as option!::some) } do { union Bar { some: str other: int none } let q = Bar::some("hello") let v = Bar::other(30) let m = Bar::none printf("q = %s, v = %d\n", q as Bar::some, v as Bar::other) } do { var addr: ipv4 addr.raw3 = 0xff01a8c0; printf("%d.%d.%d.%d\n", addr.bytes[0], addr.bytes[1], addr.bytes[2], addr.bytes[3]); } } ================================================ FILE: build/tests/using.flx ================================================ // using.flx // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. export test_using import libc as _ public fn doUsingTest() { do { enum Foo: int { case Alpha = 10 case Bravo = 20 case Charlie = 30 } using Foo as _ printf("a = %d, b = %d, c = %d\n", Alpha.value, Bravo.value, Charlie.value) using Foo as f printf("a = %d, b = %d, c = %d\n", 3 * f::Alpha.value, 3 * f::Bravo.value, 3 * f::Charlie.value) } do { class xxx { init() { } var k: T enum Foo: int { case Alpha = 71 case Bravo = 72 case Charlie = 73 } } using xxx!::Foo as _ printf("a = %d, b = %d, c = %d\n", Alpha.value, Bravo.value, Charlie.value) } do { union Option { some: T none } using Option as _ let x = some(381) let y = some("hi") printf("x = %d, y = %s\n", x as some, y as some) } do { union Option { some: T none } using Option! as _ using Option! as _ let x = some(30) let y = some("bye") printf("x = %d, y = %s\n", x as some, y as some) } } ================================================ FILE: build/tiniest.flx ================================================ // tiniest.flx // Copyright (c) 2020, zhiayang // Licensed under the Apache License Version 2.0. import libc class wrapper { init() { } static fn method(a: T, b: U) { libc::printf("t = %d, u = %d\n", typeid(a), typeid(b)); } } @entry fn main() { wrapper::method(1, "asdf") libc::printf("hello, world\n") } ================================================ FILE: build/tmp/repro_1.flx ================================================ // repro_1.flx // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. /* import libc as _ // import repro_2 as _ import repro_2 import std::limits as lim using repro_2 as _ @entry fn main() { class Foozle { init() { } static fn alpha() { } class Flub { init() { } static fn beta() { } static fn omega() { printf("owo\n") } }; } printf("four = %d\n", Foo::FOUR.value); printf("hello\n"); using Foozle::Flub as Flubzle Flubzle::omega(); printf("%d\n", Bar::bla(3)); printf("lmao\n"); let x = lim::int16::max; printf("x = %x\n", x); // let c = "a" + "b" } */ import libc import repro_3 // using libc as _ @entry fn main2() { // std::io::println("owo") // owo::println("owo") // uwu::owo::foozle() // printf("owo\n") repro_3::foozle(10) } ================================================ FILE: build/tmp/repro_2.flx ================================================ // repro_2.flx // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. public enum Foo: i32 { case ONE = 1 case TWO = 2 case FOUR = 4 } public class Bar { init() { } static fn bla(x: int) -> int => x * x } ================================================ FILE: build/tmp/repro_3.flx ================================================ // repro_3.flx // Copyright (c) 2020, zhiayang // Licensed under the Apache License Version 2.0. // public import libc as _ import libc fn foozle(x: int, y: int) -> int { return x * y } public fn foozle(x: int) { foozle(x, x + 2) // libc::printf("asdf %d\n", foozle(x, x + 2)); } ================================================ FILE: build/tmp2/a.flx ================================================ // a.flx // Copyright (c) 2020, zhiayang // Licensed under the Apache License Version 2.0. import libc as _ @entry fn main() { // let x = bazzle() * 2 // foozle(3) var i = 0 while true { defer { i += 1 } if i < -30 => break else if i > 10 => break printf("i = %d\n", i) } } ================================================ FILE: build/tmp2/b.flx ================================================ // b.flx // Copyright (c) 2020, zhiayang // Licensed under the Apache License Version 2.0. <<<<<<< Updated upstream public import c as _ public fn bazzle() -> int => 30 ======= public let INIT_TIMER: u32 = 0x00000001 public let INIT_AUDIO: u32 = 0x00000010 >>>>>>> Stashed changes ================================================ FILE: build/tmp2/c.flx ================================================ // c.flx // Copyright (c) 2020, zhiayang // Licensed under the Apache License Version 2.0. <<<<<<< Updated upstream export c ffi fn printf(fmt: &i8, ...) -> int public fn foozle(x: int) { printf("hello, world! (%d)\n", x) } ======= >>>>>>> Stashed changes ================================================ FILE: build/ultratiny.flx ================================================ // ultratiny.flx // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. export ultratiny import libc as _ import std::io as _ // import std::math @compiler_support["raii_trait::drop"] trait Drop { fn deinit() } @compiler_support["raii_trait::copy"] trait Copy { fn copy(other: &self) } @compiler_support["raii_trait::move"] trait Move { fn move(other: &mut self) } class Foo1 { init() { } deinit { printf("killed base\n"); } } class Foo : Foo1, Drop, Copy, Move { var data: int init(x: int) : super() { printf("of make (%d)\n", x) this.data = x } // fn deinit() // { // printf("is kill (%d)\n", data) // } fn copy(other: &self) { this.data = other.data printf("am copy (%d)\n", data) } fn move(other: &mut self) { this.data = other.data other.data = 0 printf("be move (%d)\n", data) } } class Bar { var data: int init(x: int) { this.data = x } } fn one() -> Foo { return Foo(x: 33) } fn two(x: Foo) { printf("x.data = %d\n", x.data) } @entry fn main() { let q = one() q.data = 17 two(q) printf("q = %d\n", q) } /* raii traits checklist: problem with deinit: in any given class implementation, the user-defined deinit *needs* to call both: (a) the inline destructor for the class (b) the user-defined destructor for the base class (c) the inline destructor for the base class so this is a bunch of work that isn't done? also, in the base class case, the derived class cannot properly define a deinit() function, because of redefinitions. what's the solution? (1) everything becomes virtual (ew) (2) method hiding (also ew) (3) ??? 3. remove the copy/move/destruct stuff from FIR? */ ================================================ FILE: changelog.md ================================================ # Partial Changelog ### 2018-12-09 `(1350296)` - fix a refcounting bug where things were getting freed too early. the cause of this bug is when we transitioned to the lvalue system, around `24addf2`, when we added arguments to the refcounting stack; we forgot to include a corresponding increment in the call argument codegen, which has since been rectified. --- ### 2018-12-08 `(201a2ce)` - allow `::` to refer to the topmost scope, like in C++ - allow `^` at any location in the scope path to refer to the parent scope -- eg. `::qux::^::foo::^::bar` (naturally will fail at the root scope!) - for some reason, added a more verbose error message when you try to use a value as a type -- it searches up the tree for an actual type with the name, and tells you how to refer to it -- using the parent-scope specifier mentioned above. --- ### 2018-12-07 `(621aea2)` - add location info to `pts` types -- which will soon need to be carried over to `fir` -- probably some kind of `TypeLocator` struct that I have in mind. - abstract away which `hash_map` we use -- preliminary tests show `ska::flat_hash_map` gives us a ~9% perf improvement across-the-board -- using the `massive.flx` and associated test framework. --- ### 2018-12-06 `(aa33f64)` - add a flag to call `abort()` on error -- now the default behaviour is to `exit(-1)`. --- ### 2018-12-06 `(f04726c)` - fixed our `std::map` implementation a bit - calls to `malloc` should go through our new malloc wrapper which checks for `null` returns - hoist `make_lval` similar to `alloca` -- was causing stack overflow issues! - apply type transforms (`poly/transforms.cpp`) in reverse, duh! surprised we didn't run into this sooner. - fix an oversight where we allowed variables to be 'used' in nested functions (due to the scoping rules implicitly), and let it slip to llvm-land (!) --- ### 2018-12-05 `(3119634)` - fixed a bug where we failed to infer union types -- was just checking the wrong thing. - add a check for unwrapping (with `as`) union values to variants with no values (eg. `opt::none`) - fixed a bug where we were not checking for duplicates when adding unresolved generic defns and operator overloads. --- ### 2018-12-04 `(2dbb858)` - fix omission of floating-point comparison ops (oops) - further patches to merge-block-elision - fix ir-block error when doing multiple logical operators (`&&` and `||`) - `is` check parses its rhs-operand the same way as `as` now (aka properly!) - add the concept of `realScope`, which is the original scope of a definition -- aka where it got defined. we need this idea because we can call `ast::typecheck()` from *any* scope, usually when instantiating generics - clean up string output to use `::` for scopes instead of `.` - change the criteria of finding an existing definition (for generic things) to only match the last N items of the current state with the stored state -- instead of the previous vice-versa situation. (ie. the current state can be smaller than the stored state) - add a distance penalty for resolving a generic function, also add a check where we don't re-add a function twice (eg. when recursively calling a generic function) - `ast::Block`s now push an anonymous scope -- no idea why they didn't. fixes a pretty massive bug where bodies of an if statement shared the same scope - probably some other misc fixes i forgot --- ### 2018-12-02 `(05b3953)` - fix a using bug (`d1a0efe`) - clean up the generated IR blocks, and implement 'merge-block-elision' properly (`76481a2`) - fix implicit method calls (that i forgot to fix after refactoring the self-handling previously) --- ### 2018-12-01 `(076e176)` - allow `export`-ing a path, eg. `std::limits`. this is different from namespacing the entire file (unlike C++), because we would then get `limits::std::...` instead - allow `import`-ing a path as well, so we can do `import std::limits as foo::bar::qux`. - `import`s of string paths (eg. `import "foo/bar"`) no longer append an `.flx` extension automatically! --- ### 2018-11-06 `(59f8469)` - flip the declaration of `ffi-as` so the external name is after `as` -- and now as a string literal (because your external names might have flax-illegal characters inside) --- ### 2018-11-06 `(a2721fc)` - declare foreign functions `as` something -- useful for OpenGL especially, (1) to deduplicate the `gl` prefix, and (2) to allow overloading of all the different `glVertex` where `N = 2, 3, 4`, `T = i, f, d` or something. --- ### 2018-11-06 `(e2f235b)` - `public` and `private` imports, where the former re-exports things and the latter is the default behaviour. --- ### 2018-11-05 `(494a01e)` - static access now uses `::` instead of `.`, along the veins of C++ and Rust. - polymorph instantiations now take the form of `Foo!<...>` (the exclamation mark) -- making it less likely to be ambiguous. - polymorph arguments can now be positional, meaning `Foo!` instead of `Foo!`. The rules are similar to that of funtion calls -- no positional arguments after named arguments. --- ### 2018-10-28 `(0b937a5)` - add chained comparison operators, eg. `10 < x < 30` would *succinctly* check for `x` between 10 and 30. - consequently, changed the precedence for all six comparison operators (`==`, `!=`, `<`, `<=`, `>`, and `>=`) to be the same (500) --- ### 2018-10-28 `(f7fd4e6)` - using unions -- including both generic and instantiated unions - vastly improved (i'd say) inference for variants of unions (when accessing them implicitly) --- ### 2018-10-27 `(e365997)` - infer polymorphs with union variants (except singleton variants) - clean up some of the `TypecheckState` god object - fixed a number of related bugs regarding namespaced generics - give polymorphic types a `TypeParamMap_t` if there was a `type_infer` --- ### 2018-10-05 `(9de42cb)` - major revamp of the generic solver -- the algorithm is mostly unchanged, but the interface and stuff is reworked. - finally implemented the iterative solver - variadic generics work - took out tuple splatting for now. --- ### 2018-07-31 `(efc961e)` - generic unions, but they're quite verbose. --- ### 2018-07-29 `(e475e99)` - add tagged union types, including support for `is` and `as` to check and unwrap respectively - infer type parameters for a type from a constructor call --- ### 2018-07-23 `(c89c809)` - fix the recursive instantiation of generic functions. --- ### 2018-07-23 `(ff2a45a)` - no longer stack allocate for arguments - new lvalue/rvalue system in the IRBuilder, to make our lives slightly easier; we no longer need to pass a value/pointer pair, and we handle the thing in the translator -- not very complicated. - add `$` as an alias for `.length` when in a subscript or slicing context, similar to how D does it. - we currently have a bug where we cannot recursively instantiate a generic function. --- ### 2018-07-16 `(fdc65d7)` - factor the any-making/getting stuff into functions for less IR mess. - fix a massive bug in `alloc` where we never called the user-code, or set the length. - add stack-allocs for arguments so we can take their address. might be in poor taste, we'll see. - enable more tests in `tester.flx`. --- ### 2018-07-15 `(70d78b4)` - fix string-literal-backslash bug. - clean up some of the old cruft lying around. - we can just make our own function called `char` that takes a slice and returns the first character. no compile-time guarantees, but until we figure out something better it's better than nothing. --- ### 2018-07-15 `(0e53fce)` - fix the bug where we were dealing incorrectly with non-generic types nested inside generic types. - fix calling variadic functions with no variadic args (by inserting an empty thing varslice in the generated arg list) - fix 0-cost casting between signed/unsigned ints causing overload failure. --- ### 2018-07-15 `(7e8322d)` - add `is` to streamline checking the `typeid` of `any` types. --- ### 2018-06-10 `(d1284a9)` - fix a bug wrt. scopes; refcount decrementing now happens at every block scope (not just loops) -- added a new `BlockPoint` thing to convey this. - fix a massive bug where `else-if` cases were never even being evaluated. - `stdio.flx`! --- ### 2018-06-10 `(1aade5f)` - replace the individual IR stuff for strings and dynamic arrays with their SAA equivalents. - add an `any` type -- kinda works like pre-rewrite. contains 32-byte internal buffer to store SAA types without additional heap allocations, types larger than 32-bytes get heap-allocated. - add `typeid()` to deal with the `any` types. --- ### 2018-06-10 `(8ab9dad)` - finally add the check for accessing `refcount` when the pointer is `null`; now we return `0` instead of crashing. --- ### 2018-06-10 `(8d9c0d2)` - fix a bug where we added generic versions for operators twice. (this caused an assertion to fire) --- ### 2018-06-10 `(aa8f9a9)` - fixed a bug wrt. passing generic stuff to generic functions -- now we check only for a subset of the generic stack instead of the whole thing when checking for existing stuff. --- ### 2018-06-08 `(e530c81)` - remove mpfr from our code --- ### 2018-06-03 `(ef6326c)` - actually fix the bug. we were previously *moving out* of arrays in a destructuring binding, which is definitely not what we want. now we increment the refcount before passing it off to the binding, so we don't prematurely free. --- ### 2018-06-03 `(4d0aa96)` - fix a massive design flaw wrt. arrays -- they now no longer modify the refcount of their elements. only when they are completely freed, then we run a decrement loop (once!) over the elements. - this should fix the linux crash as well. note: classes test fails, so we've turned that off for now. --- ### 2018-06-03 `(c060a50)` - fix a recursion bug with checking for placeholders - fix a bug where we would try to do implicit field access on non-field stuff -- set a flag during typechecking so we know. - add more tests. --- ### 2018-06-02 `(a86608b)` - fix a parsing bug involving closing braces and namespaces. --- ### 2018-06-02 `(e35c883)` - still no iterative solver, but made the error output slightly better. - also, if we're assigning the result to something with a concrete type, allow the inference thing to work with that information as well. --- ### 2018-05-31 `(dbc7cd2)` - pretty much complete implementation of the generic type solver for arbitrary levels of nesting. - one final detail is the lack of the iterative solver; that's trivial though and i'll do that on the weekend. --- ### 2018-05-28 `(1e41f88)` - fix a couple of bugs relating to SAA types and their refouncting pointers - fix a thing where single-expr functions weren't handling `doBlockEndThings` properly. - start drilling holes for the generic inference stuff --- ### 2018-05-27 `(337a6a5)` - eliminate `exitless_error`, and made everything that used to use it use our new error system. --- ### 2018-05-27 `(e479ba2)` - overhaul the error output system for non-trivial cases (it's awesome), remove `HighlightOptions` because we now have `SpanError`. - make osx travis use `tester.flx` so we stop having the CI say failed. --- ### 2018-05-27 `(6385652)` - sort the candidates by line number, and don't print too many of the fake margin/gutter things. - change typecache (thanks adrian) to be better. --- ### 2018-05-27 `(ce9f113)` - magnificently beautiful and informative errors for function call overload failure. --- ### 2018-05-18 `(80d5297)` - fix a couple of unrelated bugs - varidic arrays are now slice-based instead of dynarray-based - variadic functions work, mostly. not thoroughly tested (nothing ever is) --- ### 2018-05-03 `(65b25b3)` - parse the variadic type as `[T: ...]` - allow `[as T: x, y, ... z]` syntax for specifying explicitly that the element type should be `T`. --- ### 2018-05-03 `(25dadf0)` - remove `char` type; everything is now `i8`, and `isCharType()` just checks if its an `i8` - constructor syntax for builtin types, and strings from slices and/or ptr+data - fix a couple of mutability bugs here and there with the new gluecode. --- ### 2018-05-01 `(f3a06c3)` - actually add the instructions and stuff, fix a couple of bugs - `fir::ConstantString` is now actually a slice. - move as many of the dynamic array stuff to the new `SAA` functions as possible. - increase length when appending --- ### 2018-05-01 `(0ceb391)` - strings now behave like dynamic arrays - new concept of `SAA`, string-array-analogues (for now just strings and arrays lol) that have the `{ ptr, len, cap, refptr }` pattern. --- ### 2018-04-30 `(312b94a)` - check generic things when looking for duplicate definitions (to the best of our abilities) - actually make generic constructors work properly instead of by random chance --- ### 2018-04-30 `(1734444)` - generic functions work - made error reporting slightly better, though now it becames a little messy. --- ### 2018-04-20 `(c911408)` - actually make generic types work, because we never tested them properly last time. - fixed a bug in `pts::NamedType` that didn't take the generic mapping into account -- also fixed related issue in the parser --- ### 2018-04-20 `(860b61e)` - move to a `TCResult` thing for typechecking returns, cleans up generic types a bunch - fix a bug where we couldn't define generic types inside of a scope (eg. in a function) --- ### 2018-04-14 `(1b85906)` - make init methods always mutable, for obvious reasons. Also, virtual stuff still works and didn't break, which is a plus. --- ### 2018-04-14 `(7107d5e)` - remove all code with side effects (mostly `eat()` stuff in the parser) from within asserts. --- ### 2018-04-14 `(e9ebbb0)` - fix type-printing for the new array syntax (finally) - string literals now have a type of `[char:]`, with the appropriate implicit casts in place from `string` and to `&i8` - add implicit casting for tuple types if their elements can also be implicitly casted (trivial) - fix an issue re: constant slices in the llvm translator backend (everything was null) - distinguish appending and construct-from-two-ing for strings in the runtime-glue-code; will probably use `realloc` to implement mutating via append for strings once we get the shitty refcount madness sorted out. --- ### 2018-04-09 `(81a0eb7)` - add `[mut T:]` syntax for specifying mutable slices; otherwise they will be immutable. If using type inference, then they'll be inferred depending on what is sliced. --- ### 2018-04-08 `(f824a97)` - overhaul the mutability system to be similar to Rust; now, pointers can indicate whether the memory they point to is mutable, and `let` vs `var` only determines whether the variable itself can be modified. Use `&mut T` for the new thing. - allow `mut` to be used with methods; if it is present, then a mutable `self` is passed in, otherwise an immutable `self` is passed. - add casting to `mut`: `foo as mut` or `foo as !mut` to cast an immutable pointer/slice to a mutable one, and vice versa. - distinguish mutable and non-mutable slices, some rules about which things become mutable when sliced and which don't. --- ### 2018-04-07 `(ec9adb2)` - add generic types for structs -- presumably works for classes and stuff as well. - fix bug where we couldn't do methods in structs. - fix bug where we treated variable declarations inside method bodies as field declarations - fix bug where we were infinite-looping on method/field stuff on structs --- ### 2018-03-05 `(d9133a8)` - change type syntax to be `[T]` for dynamic arrays, `[T:]` for slices, and `[T: N]` for fixed arrays - change strings to return `[char:]` instead of making a copy of the string. This allows mutation... at your own risk (for literal strings??) - add `str` as an alias for the aforementioned `[char:]` --- ### 2018-03-04 `(b48e10f)` - change `alloc` syntax to be like this: `alloc TYPE (ARGS...) [N, M, ...] { BODY }`, where, importantly, `BODY` is code that will be run on each element in the allocated array, with bindings `it` (mutable, for obvious reasons), and `i` (immutable, again obviously) representing the current element and the index respectively. - unfortunately what we said about how `&T[]` parses was completely wrong; it parses as `&(T[])` instead. --- ### 2018-02-27 `(b89aa2c)` - fix how we did refcounts for arrays; instead of being 8 bytes behind the data pointer like we were doing for strings, they're now just stored in a separate pointer in the dynamic array struct itself. added code in appropriate places to detect null-ness of this pointer, as well as allocating + freeing it appropriately. - add for loops with tuple destructuring (in theory arbitrary destructuring, since we use the existing framework for such things). - add iteration count binding for for-loops; `for (a, b), it in foo { it == 1, 2, ... }` --- ### 2018-02-19 `(3eb36eb)` - fix the completely uncaught disaster of mismatched comparison ops in binary arithmetic - fix bug where we were double-offsetting the indices in insertvalue and extractvalue (for classes) - fix certain cases in codegen where our `TypeDefn` wasn't code-generated yet, leading to a whole host of failures. // ! STILL NOT ROBUST - fix typo in operator for division, causing it not to work properly (typoed `-` instead of `/`) - change pointer syntax to use `&T` vs `T*`. fyi, `&T[]` parses intuitively as `(&T)[]`; use `&(T[])` to get `T[]*` of old - change syntax of `alloc` (some time ago actually) to allow passing arguments to constructors; new syntax is `alloc(T, arg1, arg2, ...) [N1, N2, ...]` --- ### 2018-02-19 `(6dc5ed5)` - fix the behaviour of foreach loops such that they don't unnecessarily make values (and in the case of classes, call the constructor) for the loop variable --- ### 2018-02-19 `(f7568e9)` - add dynamic dispatch for virtual methods (WOO) - probably fix some low-key bugs somewhere --- ### 2018-02-19 `(7268a2c)` - enforce calling superclass constructor (via `init(...) : super(...)`) in class constructor definitions - fix semantics, by calling superclass inline-init function in derived-class inline-init function - refactor code internally to pull stuff out more. --- ### 2018-02-17 `(ba4de52)` - re-worked method detection (whether we're in a method or a normal function) to handle the edge case of nested function defs (specifically in a method) - make base-class declarations visible in derived classes, including via implicit-self - method hiding detection -- it is illegal to have a method in a derived class with the same signature as a method in the base class (without virtual) --- ### 2018-02-15 `(e885c8f)` - fix regression wrt. scoping and telporting in dot-ops (ref `rants.md` dated 30/11/17) --- ### 2018-02-11 `(c94a6c1)` - add `using ENUM as X`, where `X` can also be `_`. --- ### 2018-02-11 `(8123b13)` - add `using X as _` that works like import -- it copies the entities in `X` to the current scope. --- ### 2018-02-11 `(1830146)` - add `using X as Y` (but where `Y` currently cannot be `_`, and `X` must be a namespace of some kind) --- ### 2018-02-10 `(23b51a5)` - fix edge cases in dot operator, where `Some_Namespace.1234` would just typecheck 'correctly' and return `1234` as the value; we now report an error. --- ### 2018-01-28 `(00586be)` - add barebones inheritance on classes. Barebones-ness is explained in `rants.md` --- ### 2018-01-21 `(f7a72b6)` - fix variable decompositions - enable the decomposition test we had. - disable searching beyond the current scope when resolving definitions, if we already found at least one thing here. Previous behaviour was wrong, and screwed up shadowing things (would complain about ambiguous references, since we searched further up than we should've) --- ### 2018-01-21 `(1be1271)` - fix emitting `bool` in IR that was never caught because we never had a function taking `bool` args, thus we never mangled it. - add class constructors; all arguments must be named, and can only call declared init functions. --- ### 2018-01-20 `(c6a204a)` - add order-independent type usage, a-la functions. This allows `A` to refer to `B` and `A` to simultaneously refer to `B`. - fix detection (rather add it) of recursive definitions, eg. `struct A { var x: A }`, or `struct A { var x: B }; struct B { var x: A }` - add `sizeof` operator --- ### 2018-01-19 `(b7fb307)` - add static fields in classes, with working initialisers --- ### 2018-01-14 `(81faedb)` - add error backtrace, but at a great cost... --- ### 2018-01-14 `(b4dabf6)` - add splatting for single values, to fill up single-level tuple destructures, eg. `let (a, b) = ...10; a == b == 10` --- ### 2018-01-14 `(597b1f2)` - add array and tuple decomposition, and allow them to nest to arbitrarily ridiculous levels. --- ### 2018-01-14 `(f8d983c)` - allow assignment to tuples containing lvalues, to enable the tuple-swap idiom eg. `(a, b) = (b, a)` --- ### 2018-01-13 `(e91b4a2)` - add splatting of tuples in function calls; can have multiple tuples --- ### 2018-01-12 `(9e3356d)` - improve robustness by making range literals `(X...Y)` parse as binary operators instead of hacky postfix unary ops. --- ### 2018-01-07`(7cb117f)` - fix a bug that prevented parsing of function types taking 0 parameters, ie. `() -> T` --- ### 2018-01-07`(4eaae34)` - fix custom unary operators for certain cases (`@` was not being done properly, amongst other things) --- ### 2018-01-07 `(d06e235)` - add named arguments for all function calls, including methods, but excluding fn-pointer calls --- ### 2018-01-07 `(d0f8c93)` - fix some bugs re: the previous commit. --- ### 2018-01-06 `(ec728cd)` - add constructor syntax for types (as previously discussed), where you can do some fields with names, or all fields positionally. --- ### 2018-01-06 `(ec7b2f3)` - fix false assertion (assert index > 0) for InsertValue by index in FIR. Index can obviously be 0 for the first element. --- ### 2017-12-31 `(3add15b)` - fix implicit casting arguments to overloaded operators - add ability to overload unicode symbols as operators --- ### 2017-12-31 `(d2f8dbd)` - add ability to overload prefix operators - internally, move Operator to be a string type to make our lives easier with overloading. --- ### 2017-12-31 `(dcc28ba)` - fix member access on structs that were passed as arguments (ie. 'did not have pointer' -- solved by using ExtractValue in such cases) - fix method calling (same thing as above) -- but this time we need to use ImmutAlloc, because we need a `this` pointer - add basic operator overloading for binary, non-assigment operators. --- ### 2017-12-29 `(45e818e)` - check for, and error on, duplicate module imports. --- ### 2017-12-17 `(5a9aa9e)` - add deferred statements and blocks --- ### 2017-12-16 `(80a6619)` - add single-expression functions with `fn foo(a: T) -> T => a * 2` --- ### 2017-12-10 `(3b438c2)` - add support for reverse ranges (negative steps, start > end) --- ### 2017-12-10 `(f3f8dbb)` - add ranges - add foreach loops on ranges, arrays, and strings - add '=>' syntax for single-statement blocks, eg. `if x == 0 => x += 4` --- ### 2017-12-08 `(dacc809)` - fix lexing/parsing of negative numerical literals --- ### 2017-12-07 `(ca3ae4b)` - better type inference/support for empty array literals - implicit conversion from pointers to booleans for null checking --- ### 2017-12-03 `(5be4db1)` - fix runtime glue code for arrays wrt. reference counting --- ### 2017-12-02 `(e3a2b55)` - add alloc and dealloc - add dynamic array operators (`pop()`, `back()`) --- ### 2017-11-19 `(b7c6f74)` - add enums --- ### 2017-10-22 `(408260c)` - add classes ================================================ FILE: external/mpreal/mpreal.h ================================================ /* MPFR C++: Multi-precision floating point number class for C++. Based on MPFR library: http://mpfr.org Project homepage: http://www.holoborodko.com/pavel/mpfr Contact e-mail: pavel@holoborodko.com Copyright (c) 2008-2015 Pavel Holoborodko Contributors: Dmitriy Gubanov, Konstantin Holoborodko, Brian Gladman, Helmut Jarausch, Fokko Beekhof, Ulrich Mutze, Heinz van Saanen, Pere Constans, Peter van Hoof, Gael Guennebaud, Tsai Chia Cheng, Alexei Zubanov, Jauhien Piatlicki, Victor Berger, John Westwood, Petr Aleksandrov, Orion Poplawski, Charles Karney, Arash Partow, Rodney James, Jorge Leitao. Licensing: (A) MPFR C++ is under GNU General Public License ("GPL"). (B) Non-free licenses may also be purchased from the author, for users who do not want their programs protected by the GPL. The non-free licenses are for users that wish to use MPFR C++ in their products but are unwilling to release their software under the GPL (which would require them to release source code and allow free redistribution). Such users can purchase an unlimited-use license from the author. Contact us for more details. GNU General Public License ("GPL") copyright permissions statement: ************************************************************************** This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef __MPREAL_H__ #define __MPREAL_H__ #include #include #include #include #include #include #include #include #include #include #include // Options #define MPREAL_HAVE_MSVC_DEBUGVIEW // Enable Debugger Visualizer for "Debug" builds in MSVC. #define MPREAL_HAVE_DYNAMIC_STD_NUMERIC_LIMITS // Enable extended std::numeric_limits specialization. // Meaning that "digits", "round_style" and similar members are defined as functions, not constants. // See std::numeric_limits at the end of the file for more information. // Library version #define MPREAL_VERSION_MAJOR 3 #define MPREAL_VERSION_MINOR 6 #define MPREAL_VERSION_PATCHLEVEL 2 #define MPREAL_VERSION_STRING "3.6.2" // disable deprecated warnings for mpfr. #ifdef _MSC_VER #pragma warning(push, 0) #pragma warning(disable: 4996) #else #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #pragma GCC diagnostic ignored "-Wold-style-cast" #endif // Detect compiler using signatures from http://predef.sourceforge.net/ #if defined(__GNUC__) && defined(__INTEL_COMPILER) #define IsInf(x) isinf(x) // Intel ICC compiler on Linux #elif defined(_MSC_VER) // Microsoft Visual C++ #define IsInf(x) (!_finite(x)) #else #define IsInf(x) std::isinf(x) // GNU C/C++ (and/or other compilers), just hope for C99 conformance #endif // A Clang feature extension to determine compiler features. #ifndef __has_feature #define __has_feature(x) 0 #endif // Detect support for r-value references (move semantic). Borrowed from Eigen. #if (__has_feature(cxx_rvalue_references) || \ defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L || \ (defined(_MSC_VER) && _MSC_VER >= 1600)) #define MPREAL_HAVE_MOVE_SUPPORT // Use fields in mpfr_t structure to check if it was initialized / set dummy initialization #define mpfr_is_initialized(x) (0 != (x)->_mpfr_d) #define mpfr_set_uninitialized(x) ((x)->_mpfr_d = 0 ) #endif // Detect support for explicit converters. #if (__has_feature(cxx_explicit_conversions) || \ (defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC_MINOR >= 5) || __cplusplus >= 201103L || \ (defined(_MSC_VER) && _MSC_VER >= 1800)) #define MPREAL_HAVE_EXPLICIT_CONVERTERS #endif #define MPFR_USE_INTMAX_T // Enable 64-bit integer types - should be defined before mpfr.h #if defined(MPREAL_HAVE_MSVC_DEBUGVIEW) && defined(_MSC_VER) && defined(_DEBUG) #define MPREAL_MSVC_DEBUGVIEW_CODE DebugView = toString(); #define MPREAL_MSVC_DEBUGVIEW_DATA std::string DebugView; #else #define MPREAL_MSVC_DEBUGVIEW_CODE #define MPREAL_MSVC_DEBUGVIEW_DATA #endif #include #if (MPFR_VERSION < MPFR_VERSION_NUM(3,0,0)) #include // Needed for random() #endif // Less important options #define MPREAL_DOUBLE_BITS_OVERFLOW (-1) // Triggers overflow exception during conversion to double if mpreal // cannot fit in MPREAL_DOUBLE_BITS_OVERFLOW bits // = -1 disables overflow checks (default) // Fast replacement for mpfr_set_zero(x, +1): // (a) uses low-level data members, might not be compatible with new versions of MPFR // (b) sign is not set, add (x)->_mpfr_sign = 1; #define mpfr_set_zero_fast(x) ((x)->_mpfr_exp = __MPFR_EXP_ZERO) #if defined(__GNUC__) #define MPREAL_PERMISSIVE_EXPR __extension__ #else #define MPREAL_PERMISSIVE_EXPR #endif namespace mpfr { class mpreal { private: mpfr_t mp; public: // Get default rounding mode & precision inline static mp_rnd_t get_default_rnd() { return (mp_rnd_t)(mpfr_get_default_rounding_mode()); } inline static mp_prec_t get_default_prec() { return mpfr_get_default_prec(); } // Constructors && type conversions mpreal(); mpreal(const mpreal& u); mpreal(const mpf_t u); mpreal(const mpz_t u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); mpreal(const mpq_t u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); mpreal(const double u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); mpreal(const long double u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); mpreal(const unsigned long long int u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); mpreal(const long long int u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); mpreal(const unsigned long int u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); mpreal(const unsigned int u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); mpreal(const long int u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); mpreal(const int u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); // Construct mpreal from mpfr_t structure. // shared = true allows to avoid deep copy, so that mpreal and 'u' share the same data & pointers. mpreal(const mpfr_t u, bool shared = false); mpreal(const char* s, mp_prec_t prec = mpreal::get_default_prec(), int base = 10, mp_rnd_t mode = mpreal::get_default_rnd()); mpreal(const std::string& s, mp_prec_t prec = mpreal::get_default_prec(), int base = 10, mp_rnd_t mode = mpreal::get_default_rnd()); ~mpreal(); #ifdef MPREAL_HAVE_MOVE_SUPPORT mpreal& operator=(mpreal&& v) noexcept; mpreal(mpreal&& u) noexcept; #endif // Operations // = // +, -, *, /, ++, --, <<, >> // *=, +=, -=, /=, // <, >, ==, <=, >= // = mpreal& operator=(const mpreal& v); mpreal& operator=(const mpf_t v); mpreal& operator=(const mpz_t v); mpreal& operator=(const mpq_t v); mpreal& operator=(const long double v); mpreal& operator=(const double v); mpreal& operator=(const unsigned long int v); mpreal& operator=(const unsigned long long int v); mpreal& operator=(const long long int v); mpreal& operator=(const unsigned int v); mpreal& operator=(const long int v); mpreal& operator=(const int v); mpreal& operator=(const char* s); mpreal& operator=(const std::string& s); template mpreal& operator= (const std::complex& z); // + mpreal& operator+=(const mpreal& v); mpreal& operator+=(const mpf_t v); mpreal& operator+=(const mpz_t v); mpreal& operator+=(const mpq_t v); mpreal& operator+=(const long double u); mpreal& operator+=(const double u); mpreal& operator+=(const unsigned long int u); mpreal& operator+=(const unsigned int u); mpreal& operator+=(const long int u); mpreal& operator+=(const int u); mpreal& operator+=(const long long int u); mpreal& operator+=(const unsigned long long int u); mpreal& operator-=(const long long int u); mpreal& operator-=(const unsigned long long int u); mpreal& operator*=(const long long int u); mpreal& operator*=(const unsigned long long int u); mpreal& operator/=(const long long int u); mpreal& operator/=(const unsigned long long int u); const mpreal operator+() const; mpreal& operator++ (); const mpreal operator++ (int); // - mpreal& operator-=(const mpreal& v); mpreal& operator-=(const mpz_t v); mpreal& operator-=(const mpq_t v); mpreal& operator-=(const long double u); mpreal& operator-=(const double u); mpreal& operator-=(const unsigned long int u); mpreal& operator-=(const unsigned int u); mpreal& operator-=(const long int u); mpreal& operator-=(const int u); const mpreal operator-() const; friend const mpreal operator-(const unsigned long int b, const mpreal& a); friend const mpreal operator-(const unsigned int b, const mpreal& a); friend const mpreal operator-(const long int b, const mpreal& a); friend const mpreal operator-(const int b, const mpreal& a); friend const mpreal operator-(const double b, const mpreal& a); mpreal& operator-- (); const mpreal operator-- (int); // * mpreal& operator*=(const mpreal& v); mpreal& operator*=(const mpz_t v); mpreal& operator*=(const mpq_t v); mpreal& operator*=(const long double v); mpreal& operator*=(const double v); mpreal& operator*=(const unsigned long int v); mpreal& operator*=(const unsigned int v); mpreal& operator*=(const long int v); mpreal& operator*=(const int v); // / mpreal& operator/=(const mpreal& v); mpreal& operator/=(const mpz_t v); mpreal& operator/=(const mpq_t v); mpreal& operator/=(const long double v); mpreal& operator/=(const double v); mpreal& operator/=(const unsigned long int v); mpreal& operator/=(const unsigned int v); mpreal& operator/=(const long int v); mpreal& operator/=(const int v); friend const mpreal operator/(const unsigned long int b, const mpreal& a); friend const mpreal operator/(const unsigned int b, const mpreal& a); friend const mpreal operator/(const long int b, const mpreal& a); friend const mpreal operator/(const int b, const mpreal& a); friend const mpreal operator/(const double b, const mpreal& a); //<<= Fast Multiplication by 2^u mpreal& operator<<=(const unsigned long int u); mpreal& operator<<=(const unsigned int u); mpreal& operator<<=(const long int u); mpreal& operator<<=(const int u); //>>= Fast Division by 2^u mpreal& operator>>=(const unsigned long int u); mpreal& operator>>=(const unsigned int u); mpreal& operator>>=(const long int u); mpreal& operator>>=(const int u); // Type Conversion operators bool toBool ( ) const; long toLong (mp_rnd_t mode = GMP_RNDZ) const; unsigned long toULong (mp_rnd_t mode = GMP_RNDZ) const; long long toLLong (mp_rnd_t mode = GMP_RNDZ) const; unsigned long long toULLong (mp_rnd_t mode = GMP_RNDZ) const; float toFloat (mp_rnd_t mode = GMP_RNDN) const; double toDouble (mp_rnd_t mode = GMP_RNDN) const; long double toLDouble (mp_rnd_t mode = GMP_RNDN) const; #if defined (MPREAL_HAVE_EXPLICIT_CONVERTERS) explicit operator bool () const { return toBool(); } explicit operator int () const { return int(toLong()); } explicit operator long () const { return toLong(); } explicit operator long long () const { return toLLong(); } explicit operator unsigned () const { return unsigned(toULong()); } explicit operator unsigned long () const { return toULong(); } explicit operator unsigned long long () const { return toULLong(); } explicit operator float () const { return toFloat(); } explicit operator double () const { return toDouble(); } explicit operator long double () const { return toLDouble(); } #endif // Get raw pointers so that mpreal can be directly used in raw mpfr_* functions ::mpfr_ptr mpfr_ptr(); ::mpfr_srcptr mpfr_ptr() const; ::mpfr_srcptr mpfr_srcptr() const; // Convert mpreal to string with n significant digits in base b // n = -1 -> convert with the maximum available digits std::string toString(int n = -1, int b = 10, mp_rnd_t mode = mpreal::get_default_rnd()) const; #if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) std::string toString(const std::string& format) const; #endif std::ostream& output(std::ostream& os) const; // Math Functions friend const mpreal sqr (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal sqrt(const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal sqrt(const unsigned long int v, mp_rnd_t rnd_mode); friend const mpreal cbrt(const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal root(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode); friend const mpreal pow (const mpreal& a, const mpreal& b, mp_rnd_t rnd_mode); friend const mpreal pow (const mpreal& a, const mpz_t b, mp_rnd_t rnd_mode); friend const mpreal pow (const mpreal& a, const unsigned long int b, mp_rnd_t rnd_mode); friend const mpreal pow (const mpreal& a, const long int b, mp_rnd_t rnd_mode); friend const mpreal pow (const unsigned long int a, const mpreal& b, mp_rnd_t rnd_mode); friend const mpreal pow (const unsigned long int a, const unsigned long int b, mp_rnd_t rnd_mode); friend const mpreal fabs(const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal abs(const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal dim(const mpreal& a, const mpreal& b, mp_rnd_t rnd_mode); friend inline const mpreal mul_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode); friend inline const mpreal mul_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode); friend inline const mpreal div_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode); friend inline const mpreal div_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode); friend int cmpabs(const mpreal& a,const mpreal& b); friend const mpreal log (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal log2 (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal logb (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal log10(const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal exp (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal exp2 (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal exp10(const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal log1p(const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal expm1(const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal cos(const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal sin(const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal tan(const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal sec(const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal csc(const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal cot(const mpreal& v, mp_rnd_t rnd_mode); friend int sin_cos(mpreal& s, mpreal& c, const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal acos (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal asin (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal atan (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal atan2 (const mpreal& y, const mpreal& x, mp_rnd_t rnd_mode); friend const mpreal acot (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal asec (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal acsc (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal cosh (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal sinh (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal tanh (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal sech (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal csch (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal coth (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal acosh (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal asinh (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal atanh (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal acoth (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal asech (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal acsch (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal hypot (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); friend const mpreal fac_ui (unsigned long int v, mp_prec_t prec, mp_rnd_t rnd_mode); friend const mpreal eint (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal gamma (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal tgamma (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal lngamma (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal lgamma (const mpreal& v, int *signp, mp_rnd_t rnd_mode); friend const mpreal zeta (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal erf (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal erfc (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal besselj0 (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal besselj1 (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal besseljn (long n, const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal bessely0 (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal bessely1 (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal besselyn (long n, const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal fma (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode); friend const mpreal fms (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode); friend const mpreal agm (const mpreal& v1, const mpreal& v2, mp_rnd_t rnd_mode); friend const mpreal sum (const mpreal tab[], const unsigned long int n, int& status, mp_rnd_t rnd_mode); friend int sgn(const mpreal& v); // returns -1 or +1 // MPFR 2.4.0 Specifics #if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) friend int sinh_cosh (mpreal& s, mpreal& c, const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal li2 (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal fmod (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); friend const mpreal rec_sqrt (const mpreal& v, mp_rnd_t rnd_mode); // MATLAB's semantic equivalents friend const mpreal rem (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); // Remainder after division friend const mpreal mod (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); // Modulus after division #endif #if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) friend const mpreal digamma (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal ai (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal urandom (gmp_randstate_t& state, mp_rnd_t rnd_mode); // use gmp_randinit_default() to init state, gmp_randclear() to clear #endif #if (MPFR_VERSION >= MPFR_VERSION_NUM(3,1,0)) friend const mpreal grandom (gmp_randstate_t& state, mp_rnd_t rnd_mode); // use gmp_randinit_default() to init state, gmp_randclear() to clear friend const mpreal grandom (unsigned int seed); #endif // Uniformly distributed random number generation in [0,1] using // Mersenne-Twister algorithm by default. // Use parameter to setup seed, e.g.: random((unsigned)time(NULL)) // Check urandom() for more precise control. friend const mpreal random(unsigned int seed); // Exponent and mantissa manipulation friend const mpreal frexp (const mpreal& v, mp_exp_t* exp); friend const mpreal ldexp (const mpreal& v, mp_exp_t exp); friend const mpreal scalbn(const mpreal& v, mp_exp_t exp); // Splits mpreal value into fractional and integer parts. // Returns fractional part and stores integer part in n. friend const mpreal modf(const mpreal& v, mpreal& n); // Constants // don't forget to call mpfr_free_cache() for every thread where you are using const-functions friend const mpreal const_log2 (mp_prec_t prec, mp_rnd_t rnd_mode); friend const mpreal const_pi (mp_prec_t prec, mp_rnd_t rnd_mode); friend const mpreal const_euler (mp_prec_t prec, mp_rnd_t rnd_mode); friend const mpreal const_catalan (mp_prec_t prec, mp_rnd_t rnd_mode); // returns +inf iff sign>=0 otherwise -inf friend const mpreal const_infinity(int sign, mp_prec_t prec); // Output/ Input friend std::ostream& operator<<(std::ostream& os, const mpreal& v); friend std::istream& operator>>(std::istream& is, mpreal& v); // Integer Related Functions friend const mpreal rint (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal ceil (const mpreal& v); friend const mpreal floor(const mpreal& v); friend const mpreal round(const mpreal& v); friend const mpreal trunc(const mpreal& v); friend const mpreal rint_ceil (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal rint_floor (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal rint_round (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal rint_trunc (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal frac (const mpreal& v, mp_rnd_t rnd_mode); friend const mpreal remainder ( const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); friend const mpreal remquo (long* q, const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); // Miscellaneous Functions friend const mpreal nexttoward (const mpreal& x, const mpreal& y); friend const mpreal nextabove (const mpreal& x); friend const mpreal nextbelow (const mpreal& x); // use gmp_randinit_default() to init state, gmp_randclear() to clear friend const mpreal urandomb (gmp_randstate_t& state); // MPFR < 2.4.2 Specifics #if (MPFR_VERSION <= MPFR_VERSION_NUM(2,4,2)) friend const mpreal random2 (mp_size_t size, mp_exp_t exp); #endif // Instance Checkers friend bool isnan (const mpreal& v); friend bool isinf (const mpreal& v); friend bool isfinite (const mpreal& v); friend bool isnum (const mpreal& v); friend bool iszero (const mpreal& v); friend bool isint (const mpreal& v); #if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) friend bool isregular(const mpreal& v); #endif // Set/Get instance properties inline mp_prec_t get_prec() const; inline void set_prec(mp_prec_t prec, mp_rnd_t rnd_mode = get_default_rnd()); // Change precision with rounding mode // Aliases for get_prec(), set_prec() - needed for compatibility with std::complex interface inline mpreal& setPrecision(int Precision, mp_rnd_t RoundingMode = get_default_rnd()); inline int getPrecision() const; // Set mpreal to +/- inf, NaN, +/-0 mpreal& setInf (int Sign = +1); mpreal& setNan (); mpreal& setZero (int Sign = +1); mpreal& setSign (int Sign, mp_rnd_t RoundingMode = get_default_rnd()); //Exponent mp_exp_t get_exp(); int set_exp(mp_exp_t e); int check_range (int t, mp_rnd_t rnd_mode = get_default_rnd()); int subnormalize (int t, mp_rnd_t rnd_mode = get_default_rnd()); // Inexact conversion from float inline bool fits_in_bits(double x, int n); // Set/Get global properties static void set_default_prec(mp_prec_t prec); static void set_default_rnd(mp_rnd_t rnd_mode); static mp_exp_t get_emin (void); static mp_exp_t get_emax (void); static mp_exp_t get_emin_min (void); static mp_exp_t get_emin_max (void); static mp_exp_t get_emax_min (void); static mp_exp_t get_emax_max (void); static int set_emin (mp_exp_t exp); static int set_emax (mp_exp_t exp); // Efficient swapping of two mpreal values - needed for std algorithms friend void swap(mpreal& x, mpreal& y); friend const mpreal fmax(const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); friend const mpreal fmin(const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); private: // Human friendly Debug Preview in Visual Studio. // Put one of these lines: // // mpfr::mpreal= ; Show value only // mpfr::mpreal=, bits ; Show value & precision // // at the beginning of // [Visual Studio Installation Folder]\Common7\Packages\Debugger\autoexp.dat MPREAL_MSVC_DEBUGVIEW_DATA // "Smart" resources deallocation. Checks if instance initialized before deletion. void clear(::mpfr_ptr); }; ////////////////////////////////////////////////////////////////////////// // Exceptions class conversion_overflow : public std::exception { public: std::string why() { return "inexact conversion from floating point"; } }; ////////////////////////////////////////////////////////////////////////// // Constructors & converters // Default constructor: creates mp number and initializes it to 0. inline mpreal::mpreal() { mpfr_init2(mpfr_ptr(), mpreal::get_default_prec()); mpfr_set_zero_fast(mpfr_ptr()); MPREAL_MSVC_DEBUGVIEW_CODE; } inline mpreal::mpreal(const mpreal& u) { mpfr_init2(mpfr_ptr(),mpfr_get_prec(u.mpfr_srcptr())); mpfr_set (mpfr_ptr(),u.mpfr_srcptr(),mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; } #ifdef MPREAL_HAVE_MOVE_SUPPORT inline mpreal::mpreal(mpreal&& other) noexcept { mpfr_set_uninitialized(mpfr_ptr()); // make sure "other" holds no pointer to actual data mpfr_swap(mpfr_ptr(), other.mpfr_ptr()); MPREAL_MSVC_DEBUGVIEW_CODE; } inline mpreal& mpreal::operator=(mpreal&& other) noexcept { mpfr_swap(mpfr_ptr(), other.mpfr_ptr()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } #endif inline mpreal::mpreal(const mpfr_t u, bool shared) { if(shared) { std::memcpy(mpfr_ptr(), u, sizeof(mpfr_t)); } else { mpfr_init2(mpfr_ptr(), mpfr_get_prec(u)); mpfr_set (mpfr_ptr(), u, mpreal::get_default_rnd()); } MPREAL_MSVC_DEBUGVIEW_CODE; } inline mpreal::mpreal(const mpf_t u) { mpfr_init2(mpfr_ptr(),(mp_prec_t) mpf_get_prec(u)); // (gmp: mp_bitcnt_t) unsigned long -> long (mpfr: mp_prec_t) mpfr_set_f(mpfr_ptr(),u,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; } inline mpreal::mpreal(const mpz_t u, mp_prec_t prec, mp_rnd_t mode) { mpfr_init2(mpfr_ptr(), prec); mpfr_set_z(mpfr_ptr(), u, mode); MPREAL_MSVC_DEBUGVIEW_CODE; } inline mpreal::mpreal(const mpq_t u, mp_prec_t prec, mp_rnd_t mode) { mpfr_init2(mpfr_ptr(), prec); mpfr_set_q(mpfr_ptr(), u, mode); MPREAL_MSVC_DEBUGVIEW_CODE; } inline mpreal::mpreal(const double u, mp_prec_t prec, mp_rnd_t mode) { mpfr_init2(mpfr_ptr(), prec); #if (MPREAL_DOUBLE_BITS_OVERFLOW > -1) if(fits_in_bits(u, MPREAL_DOUBLE_BITS_OVERFLOW)) { mpfr_set_d(mpfr_ptr(), u, mode); }else throw conversion_overflow(); #else mpfr_set_d(mpfr_ptr(), u, mode); #endif MPREAL_MSVC_DEBUGVIEW_CODE; } inline mpreal::mpreal(const long double u, mp_prec_t prec, mp_rnd_t mode) { mpfr_init2 (mpfr_ptr(), prec); mpfr_set_ld(mpfr_ptr(), u, mode); MPREAL_MSVC_DEBUGVIEW_CODE; } inline mpreal::mpreal(const unsigned long long int u, mp_prec_t prec, mp_rnd_t mode) { mpfr_init2 (mpfr_ptr(), prec); mpfr_set_uj(mpfr_ptr(), u, mode); MPREAL_MSVC_DEBUGVIEW_CODE; } inline mpreal::mpreal(const long long int u, mp_prec_t prec, mp_rnd_t mode) { mpfr_init2 (mpfr_ptr(), prec); mpfr_set_sj(mpfr_ptr(), u, mode); MPREAL_MSVC_DEBUGVIEW_CODE; } inline mpreal::mpreal(const unsigned long int u, mp_prec_t prec, mp_rnd_t mode) { mpfr_init2 (mpfr_ptr(), prec); mpfr_set_ui(mpfr_ptr(), u, mode); MPREAL_MSVC_DEBUGVIEW_CODE; } inline mpreal::mpreal(const unsigned int u, mp_prec_t prec, mp_rnd_t mode) { mpfr_init2 (mpfr_ptr(), prec); mpfr_set_ui(mpfr_ptr(), u, mode); MPREAL_MSVC_DEBUGVIEW_CODE; } inline mpreal::mpreal(const long int u, mp_prec_t prec, mp_rnd_t mode) { mpfr_init2 (mpfr_ptr(), prec); mpfr_set_si(mpfr_ptr(), u, mode); MPREAL_MSVC_DEBUGVIEW_CODE; } inline mpreal::mpreal(const int u, mp_prec_t prec, mp_rnd_t mode) { mpfr_init2 (mpfr_ptr(), prec); mpfr_set_si(mpfr_ptr(), u, mode); MPREAL_MSVC_DEBUGVIEW_CODE; } inline mpreal::mpreal(const char* s, mp_prec_t prec, int base, mp_rnd_t mode) { mpfr_init2 (mpfr_ptr(), prec); mpfr_set_str(mpfr_ptr(), s, base, mode); MPREAL_MSVC_DEBUGVIEW_CODE; } inline mpreal::mpreal(const std::string& s, mp_prec_t prec, int base, mp_rnd_t mode) { mpfr_init2 (mpfr_ptr(), prec); mpfr_set_str(mpfr_ptr(), s.c_str(), base, mode); MPREAL_MSVC_DEBUGVIEW_CODE; } inline void mpreal::clear(::mpfr_ptr x) { #ifdef MPREAL_HAVE_MOVE_SUPPORT if(mpfr_is_initialized(x)) #endif mpfr_clear(x); } inline mpreal::~mpreal() { clear(mpfr_ptr()); } // internal namespace needed for template magic namespace internal{ // Use SFINAE to restrict arithmetic operations instantiation only for numeric types // This is needed for smooth integration with libraries based on expression templates, like Eigen. // TODO: Do the same for boolean operators. template struct result_type {}; template <> struct result_type {typedef mpreal type;}; template <> struct result_type {typedef mpreal type;}; template <> struct result_type {typedef mpreal type;}; template <> struct result_type {typedef mpreal type;}; template <> struct result_type {typedef mpreal type;}; template <> struct result_type {typedef mpreal type;}; template <> struct result_type {typedef mpreal type;}; template <> struct result_type {typedef mpreal type;}; template <> struct result_type {typedef mpreal type;}; template <> struct result_type {typedef mpreal type;}; template <> struct result_type {typedef mpreal type;}; } // + Addition template inline const typename internal::result_type::type operator+(const mpreal& lhs, const Rhs& rhs){ return mpreal(lhs) += rhs; } template inline const typename internal::result_type::type operator+(const Lhs& lhs, const mpreal& rhs){ return mpreal(rhs) += lhs; } // - Subtraction template inline const typename internal::result_type::type operator-(const mpreal& lhs, const Rhs& rhs){ return mpreal(lhs) -= rhs; } template inline const typename internal::result_type::type operator-(const Lhs& lhs, const mpreal& rhs){ return mpreal(lhs) -= rhs; } // * Multiplication template inline const typename internal::result_type::type operator*(const mpreal& lhs, const Rhs& rhs){ return mpreal(lhs) *= rhs; } template inline const typename internal::result_type::type operator*(const Lhs& lhs, const mpreal& rhs){ return mpreal(rhs) *= lhs; } // / Division template inline const typename internal::result_type::type operator/(const mpreal& lhs, const Rhs& rhs){ return mpreal(lhs) /= rhs; } template inline const typename internal::result_type::type operator/(const Lhs& lhs, const mpreal& rhs){ return mpreal(lhs) /= rhs; } ////////////////////////////////////////////////////////////////////////// // sqrt const mpreal sqrt(const unsigned int v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal sqrt(const long int v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal sqrt(const int v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal sqrt(const long double v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal sqrt(const double v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); // abs inline const mpreal abs(const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()); ////////////////////////////////////////////////////////////////////////// // pow const mpreal pow(const mpreal& a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const mpreal& a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const mpreal& a, const long double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const mpreal& a, const double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const unsigned int a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const long int a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const int a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const long double a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const double a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const unsigned long int a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const unsigned long int a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const unsigned long int a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const unsigned long int a, const long double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const unsigned long int a, const double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const unsigned int a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const unsigned int a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const unsigned int a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const unsigned int a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const unsigned int a, const long double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const unsigned int a, const double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const long int a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const long int a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const long int a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const long int a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const long int a, const long double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const long int a, const double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const int a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const int a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const int a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const int a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const int a, const long double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const int a, const double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const long double a, const long double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const long double a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const long double a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const long double a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const long double a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const double a, const double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const double a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const double a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const double a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); const mpreal pow(const double a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); inline const mpreal mul_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); inline const mpreal mul_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); inline const mpreal div_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); inline const mpreal div_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); ////////////////////////////////////////////////////////////////////////// // Estimate machine epsilon for the given precision // Returns smallest eps such that 1.0 + eps != 1.0 inline mpreal machine_epsilon(mp_prec_t prec = mpreal::get_default_prec()); // Returns smallest eps such that x + eps != x (relative machine epsilon) inline mpreal machine_epsilon(const mpreal& x); // Gives max & min values for the required precision, // minval is 'safe' meaning 1 / minval does not overflow // maxval is 'safe' meaning 1 / maxval does not underflow inline mpreal minval(mp_prec_t prec = mpreal::get_default_prec()); inline mpreal maxval(mp_prec_t prec = mpreal::get_default_prec()); // 'Dirty' equality check 1: |a-b| < min{|a|,|b|} * eps inline bool isEqualFuzzy(const mpreal& a, const mpreal& b, const mpreal& eps); // 'Dirty' equality check 2: |a-b| < min{|a|,|b|} * eps( min{|a|,|b|} ) inline bool isEqualFuzzy(const mpreal& a, const mpreal& b); // 'Bitwise' equality check // maxUlps - a and b can be apart by maxUlps binary numbers. inline bool isEqualUlps(const mpreal& a, const mpreal& b, int maxUlps); ////////////////////////////////////////////////////////////////////////// // Convert precision in 'bits' to decimal digits and vice versa. // bits = ceil(digits*log[2](10)) // digits = floor(bits*log[10](2)) inline mp_prec_t digits2bits(int d); inline int bits2digits(mp_prec_t b); ////////////////////////////////////////////////////////////////////////// // min, max const mpreal (max)(const mpreal& x, const mpreal& y); const mpreal (min)(const mpreal& x, const mpreal& y); ////////////////////////////////////////////////////////////////////////// // Implementation ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // Operators - Assignment inline mpreal& mpreal::operator=(const mpreal& v) { if (this != &v) { mp_prec_t tp = mpfr_get_prec( mpfr_srcptr()); mp_prec_t vp = mpfr_get_prec(v.mpfr_srcptr()); if(tp != vp){ clear(mpfr_ptr()); mpfr_init2(mpfr_ptr(), vp); } mpfr_set(mpfr_ptr(), v.mpfr_srcptr(), mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; } return *this; } inline mpreal& mpreal::operator=(const mpf_t v) { mpfr_set_f(mpfr_ptr(), v, mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator=(const mpz_t v) { mpfr_set_z(mpfr_ptr(), v, mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator=(const mpq_t v) { mpfr_set_q(mpfr_ptr(), v, mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator=(const long double v) { mpfr_set_ld(mpfr_ptr(), v, mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator=(const double v) { #if (MPREAL_DOUBLE_BITS_OVERFLOW > -1) if(fits_in_bits(v, MPREAL_DOUBLE_BITS_OVERFLOW)) { mpfr_set_d(mpfr_ptr(),v,mpreal::get_default_rnd()); }else throw conversion_overflow(); #else mpfr_set_d(mpfr_ptr(),v,mpreal::get_default_rnd()); #endif MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator=(const unsigned long int v) { mpfr_set_ui(mpfr_ptr(), v, mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator=(const unsigned int v) { mpfr_set_ui(mpfr_ptr(), v, mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator=(const unsigned long long int v) { mpfr_set_uj(mpfr_ptr(), v, mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator=(const long long int v) { mpfr_set_sj(mpfr_ptr(), v, mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator=(const long int v) { mpfr_set_si(mpfr_ptr(), v, mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator=(const int v) { mpfr_set_si(mpfr_ptr(), v, mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator=(const char* s) { // Use other converters for more precise control on base & precision & rounding: // // mpreal(const char* s, mp_prec_t prec, int base, mp_rnd_t mode) // mpreal(const std::string& s,mp_prec_t prec, int base, mp_rnd_t mode) // // Here we assume base = 10 and we use precision of target variable. mpfr_t t; mpfr_init2(t, mpfr_get_prec(mpfr_srcptr())); if(0 == mpfr_set_str(t, s, 10, mpreal::get_default_rnd())) { mpfr_set(mpfr_ptr(), t, mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; } clear(t); return *this; } inline mpreal& mpreal::operator=(const std::string& s) { // Use other converters for more precise control on base & precision & rounding: // // mpreal(const char* s, mp_prec_t prec, int base, mp_rnd_t mode) // mpreal(const std::string& s,mp_prec_t prec, int base, mp_rnd_t mode) // // Here we assume base = 10 and we use precision of target variable. mpfr_t t; mpfr_init2(t, mpfr_get_prec(mpfr_srcptr())); if(0 == mpfr_set_str(t, s.c_str(), 10, mpreal::get_default_rnd())) { mpfr_set(mpfr_ptr(), t, mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; } clear(t); return *this; } template inline mpreal& mpreal::operator= (const std::complex& z) { *this = z.real(); return *this; } ////////////////////////////////////////////////////////////////////////// // + Addition inline mpreal& mpreal::operator+=(const mpreal& v) { mpfr_add(mpfr_ptr(), mpfr_srcptr(), v.mpfr_srcptr(), mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator+=(const mpf_t u) { *this += mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator+=(const mpz_t u) { mpfr_add_z(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator+=(const mpq_t u) { mpfr_add_q(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator+= (const long double u) { *this += mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator+= (const double u) { #if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) mpfr_add_d(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); #else *this += mpreal(u); #endif MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator+=(const unsigned long int u) { mpfr_add_ui(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator+=(const unsigned int u) { mpfr_add_ui(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator+=(const long int u) { mpfr_add_si(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator+=(const int u) { mpfr_add_si(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator+=(const long long int u) { *this += mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator+=(const unsigned long long int u){ *this += mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator-=(const long long int u) { *this -= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator-=(const unsigned long long int u){ *this -= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator*=(const long long int u) { *this *= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator*=(const unsigned long long int u){ *this *= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator/=(const long long int u) { *this /= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator/=(const unsigned long long int u){ *this /= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline const mpreal mpreal::operator+()const { return mpreal(*this); } inline const mpreal operator+(const mpreal& a, const mpreal& b) { mpreal c(0, (std::max)(mpfr_get_prec(a.mpfr_ptr()), mpfr_get_prec(b.mpfr_ptr()))); mpfr_add(c.mpfr_ptr(), a.mpfr_srcptr(), b.mpfr_srcptr(), mpreal::get_default_rnd()); return c; } inline mpreal& mpreal::operator++() { return *this += 1; } inline const mpreal mpreal::operator++ (int) { mpreal x(*this); *this += 1; return x; } inline mpreal& mpreal::operator--() { return *this -= 1; } inline const mpreal mpreal::operator-- (int) { mpreal x(*this); *this -= 1; return x; } ////////////////////////////////////////////////////////////////////////// // - Subtraction inline mpreal& mpreal::operator-=(const mpreal& v) { mpfr_sub(mpfr_ptr(),mpfr_srcptr(),v.mpfr_srcptr(),mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator-=(const mpz_t v) { mpfr_sub_z(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator-=(const mpq_t v) { mpfr_sub_q(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator-=(const long double v) { *this -= mpreal(v); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator-=(const double v) { #if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) mpfr_sub_d(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); #else *this -= mpreal(v); #endif MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator-=(const unsigned long int v) { mpfr_sub_ui(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator-=(const unsigned int v) { mpfr_sub_ui(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator-=(const long int v) { mpfr_sub_si(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator-=(const int v) { mpfr_sub_si(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline const mpreal mpreal::operator-()const { mpreal u(*this); mpfr_neg(u.mpfr_ptr(),u.mpfr_srcptr(),mpreal::get_default_rnd()); return u; } inline const mpreal operator-(const mpreal& a, const mpreal& b) { mpreal c(0, (std::max)(mpfr_get_prec(a.mpfr_ptr()), mpfr_get_prec(b.mpfr_ptr()))); mpfr_sub(c.mpfr_ptr(), a.mpfr_srcptr(), b.mpfr_srcptr(), mpreal::get_default_rnd()); return c; } inline const mpreal operator-(const double b, const mpreal& a) { #if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) mpreal x(0, mpfr_get_prec(a.mpfr_ptr())); mpfr_d_sub(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); return x; #else mpreal x(b, mpfr_get_prec(a.mpfr_ptr())); x -= a; return x; #endif } inline const mpreal operator-(const unsigned long int b, const mpreal& a) { mpreal x(0, mpfr_get_prec(a.mpfr_ptr())); mpfr_ui_sub(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); return x; } inline const mpreal operator-(const unsigned int b, const mpreal& a) { mpreal x(0, mpfr_get_prec(a.mpfr_ptr())); mpfr_ui_sub(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); return x; } inline const mpreal operator-(const long int b, const mpreal& a) { mpreal x(0, mpfr_get_prec(a.mpfr_ptr())); mpfr_si_sub(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); return x; } inline const mpreal operator-(const int b, const mpreal& a) { mpreal x(0, mpfr_get_prec(a.mpfr_ptr())); mpfr_si_sub(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); return x; } ////////////////////////////////////////////////////////////////////////// // * Multiplication inline mpreal& mpreal::operator*= (const mpreal& v) { mpfr_mul(mpfr_ptr(),mpfr_srcptr(),v.mpfr_srcptr(),mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator*=(const mpz_t v) { mpfr_mul_z(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator*=(const mpq_t v) { mpfr_mul_q(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator*=(const long double v) { *this *= mpreal(v); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator*=(const double v) { #if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) mpfr_mul_d(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); #else *this *= mpreal(v); #endif MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator*=(const unsigned long int v) { mpfr_mul_ui(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator*=(const unsigned int v) { mpfr_mul_ui(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator*=(const long int v) { mpfr_mul_si(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator*=(const int v) { mpfr_mul_si(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline const mpreal operator*(const mpreal& a, const mpreal& b) { mpreal c(0, (std::max)(mpfr_get_prec(a.mpfr_ptr()), mpfr_get_prec(b.mpfr_ptr()))); mpfr_mul(c.mpfr_ptr(), a.mpfr_srcptr(), b.mpfr_srcptr(), mpreal::get_default_rnd()); return c; } ////////////////////////////////////////////////////////////////////////// // / Division inline mpreal& mpreal::operator/=(const mpreal& v) { mpfr_div(mpfr_ptr(),mpfr_srcptr(),v.mpfr_srcptr(),mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator/=(const mpz_t v) { mpfr_div_z(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator/=(const mpq_t v) { mpfr_div_q(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator/=(const long double v) { *this /= mpreal(v); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator/=(const double v) { #if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) mpfr_div_d(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); #else *this /= mpreal(v); #endif MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator/=(const unsigned long int v) { mpfr_div_ui(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator/=(const unsigned int v) { mpfr_div_ui(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator/=(const long int v) { mpfr_div_si(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator/=(const int v) { mpfr_div_si(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline const mpreal operator/(const mpreal& a, const mpreal& b) { mpreal c(0, (std::max)(mpfr_get_prec(a.mpfr_srcptr()), mpfr_get_prec(b.mpfr_srcptr()))); mpfr_div(c.mpfr_ptr(), a.mpfr_srcptr(), b.mpfr_srcptr(), mpreal::get_default_rnd()); return c; } inline const mpreal operator/(const unsigned long int b, const mpreal& a) { mpreal x(0, mpfr_get_prec(a.mpfr_srcptr())); mpfr_ui_div(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); return x; } inline const mpreal operator/(const unsigned int b, const mpreal& a) { mpreal x(0, mpfr_get_prec(a.mpfr_srcptr())); mpfr_ui_div(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); return x; } inline const mpreal operator/(const long int b, const mpreal& a) { mpreal x(0, mpfr_get_prec(a.mpfr_srcptr())); mpfr_si_div(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); return x; } inline const mpreal operator/(const int b, const mpreal& a) { mpreal x(0, mpfr_get_prec(a.mpfr_srcptr())); mpfr_si_div(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); return x; } inline const mpreal operator/(const double b, const mpreal& a) { #if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) mpreal x(0, mpfr_get_prec(a.mpfr_srcptr())); mpfr_d_div(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); return x; #else mpreal x(0, mpfr_get_prec(a.mpfr_ptr())); x /= a; return x; #endif } ////////////////////////////////////////////////////////////////////////// // Shifts operators - Multiplication/Division by power of 2 inline mpreal& mpreal::operator<<=(const unsigned long int u) { mpfr_mul_2ui(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator<<=(const unsigned int u) { mpfr_mul_2ui(mpfr_ptr(),mpfr_srcptr(),static_cast(u),mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator<<=(const long int u) { mpfr_mul_2si(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator<<=(const int u) { mpfr_mul_2si(mpfr_ptr(),mpfr_srcptr(),static_cast(u),mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator>>=(const unsigned long int u) { mpfr_div_2ui(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator>>=(const unsigned int u) { mpfr_div_2ui(mpfr_ptr(),mpfr_srcptr(),static_cast(u),mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator>>=(const long int u) { mpfr_div_2si(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::operator>>=(const int u) { mpfr_div_2si(mpfr_ptr(),mpfr_srcptr(),static_cast(u),mpreal::get_default_rnd()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline const mpreal operator<<(const mpreal& v, const unsigned long int k) { return mul_2ui(v,k); } inline const mpreal operator<<(const mpreal& v, const unsigned int k) { return mul_2ui(v,static_cast(k)); } inline const mpreal operator<<(const mpreal& v, const long int k) { return mul_2si(v,k); } inline const mpreal operator<<(const mpreal& v, const int k) { return mul_2si(v,static_cast(k)); } inline const mpreal operator>>(const mpreal& v, const unsigned long int k) { return div_2ui(v,k); } inline const mpreal operator>>(const mpreal& v, const long int k) { return div_2si(v,k); } inline const mpreal operator>>(const mpreal& v, const unsigned int k) { return div_2ui(v,static_cast(k)); } inline const mpreal operator>>(const mpreal& v, const int k) { return div_2si(v,static_cast(k)); } // mul_2ui inline const mpreal mul_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode) { mpreal x(v); mpfr_mul_2ui(x.mpfr_ptr(),v.mpfr_srcptr(),k,rnd_mode); return x; } // mul_2si inline const mpreal mul_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode) { mpreal x(v); mpfr_mul_2si(x.mpfr_ptr(),v.mpfr_srcptr(),k,rnd_mode); return x; } inline const mpreal div_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode) { mpreal x(v); mpfr_div_2ui(x.mpfr_ptr(),v.mpfr_srcptr(),k,rnd_mode); return x; } inline const mpreal div_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode) { mpreal x(v); mpfr_div_2si(x.mpfr_ptr(),v.mpfr_srcptr(),k,rnd_mode); return x; } ////////////////////////////////////////////////////////////////////////// //Relational operators // WARNING: // // Please note that following checks for double-NaN are guaranteed to work only in IEEE math mode: // // isnan(b) = (b != b) // isnan(b) = !(b == b) (we use in code below) // // Be cautions if you use compiler options which break strict IEEE compliance (e.g. -ffast-math in GCC). // Use std::isnan instead (C++11). inline bool operator > (const mpreal& a, const mpreal& b ){ return (mpfr_greater_p(a.mpfr_srcptr(),b.mpfr_srcptr()) != 0 ); } inline bool operator > (const mpreal& a, const unsigned long int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) > 0 ); } inline bool operator > (const mpreal& a, const unsigned int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) > 0 ); } inline bool operator > (const mpreal& a, const long int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) > 0 ); } inline bool operator > (const mpreal& a, const int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) > 0 ); } inline bool operator > (const mpreal& a, const long double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_ld(a.mpfr_srcptr(),b) > 0 ); } inline bool operator > (const mpreal& a, const double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_d (a.mpfr_srcptr(),b) > 0 ); } inline bool operator >= (const mpreal& a, const mpreal& b ){ return (mpfr_greaterequal_p(a.mpfr_srcptr(),b.mpfr_srcptr()) != 0 ); } inline bool operator >= (const mpreal& a, const unsigned long int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) >= 0 ); } inline bool operator >= (const mpreal& a, const unsigned int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) >= 0 ); } inline bool operator >= (const mpreal& a, const long int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) >= 0 ); } inline bool operator >= (const mpreal& a, const int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) >= 0 ); } inline bool operator >= (const mpreal& a, const long double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_ld(a.mpfr_srcptr(),b) >= 0 ); } inline bool operator >= (const mpreal& a, const double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_d (a.mpfr_srcptr(),b) >= 0 ); } inline bool operator < (const mpreal& a, const mpreal& b ){ return (mpfr_less_p(a.mpfr_srcptr(),b.mpfr_srcptr()) != 0 ); } inline bool operator < (const mpreal& a, const unsigned long int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) < 0 ); } inline bool operator < (const mpreal& a, const unsigned int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) < 0 ); } inline bool operator < (const mpreal& a, const long int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) < 0 ); } inline bool operator < (const mpreal& a, const int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) < 0 ); } inline bool operator < (const mpreal& a, const long double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_ld(a.mpfr_srcptr(),b) < 0 ); } inline bool operator < (const mpreal& a, const double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_d (a.mpfr_srcptr(),b) < 0 ); } inline bool operator <= (const mpreal& a, const mpreal& b ){ return (mpfr_lessequal_p(a.mpfr_srcptr(),b.mpfr_srcptr()) != 0 ); } inline bool operator <= (const mpreal& a, const unsigned long int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) <= 0 ); } inline bool operator <= (const mpreal& a, const unsigned int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) <= 0 ); } inline bool operator <= (const mpreal& a, const long int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) <= 0 ); } inline bool operator <= (const mpreal& a, const int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) <= 0 ); } inline bool operator <= (const mpreal& a, const long double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_ld(a.mpfr_srcptr(),b) <= 0 ); } inline bool operator <= (const mpreal& a, const double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_d (a.mpfr_srcptr(),b) <= 0 ); } inline bool operator == (const mpreal& a, const mpreal& b ){ return (mpfr_equal_p(a.mpfr_srcptr(),b.mpfr_srcptr()) != 0 ); } inline bool operator == (const mpreal& a, const unsigned long int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) == 0 ); } inline bool operator == (const mpreal& a, const unsigned int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) == 0 ); } inline bool operator == (const mpreal& a, const long int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) == 0 ); } inline bool operator == (const mpreal& a, const int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) == 0 ); } inline bool operator == (const mpreal& a, const long double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_ld(a.mpfr_srcptr(),b) == 0 ); } inline bool operator == (const mpreal& a, const double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_d (a.mpfr_srcptr(),b) == 0 ); } inline bool operator != (const mpreal& a, const mpreal& b ){ return !(a == b); } inline bool operator != (const mpreal& a, const unsigned long int b ){ return !(a == b); } inline bool operator != (const mpreal& a, const unsigned int b ){ return !(a == b); } inline bool operator != (const mpreal& a, const long int b ){ return !(a == b); } inline bool operator != (const mpreal& a, const int b ){ return !(a == b); } inline bool operator != (const mpreal& a, const long double b ){ return !(a == b); } inline bool operator != (const mpreal& a, const double b ){ return !(a == b); } inline bool isnan (const mpreal& op){ return (mpfr_nan_p (op.mpfr_srcptr()) != 0 ); } inline bool isinf (const mpreal& op){ return (mpfr_inf_p (op.mpfr_srcptr()) != 0 ); } inline bool isfinite (const mpreal& op){ return (mpfr_number_p (op.mpfr_srcptr()) != 0 ); } inline bool iszero (const mpreal& op){ return (mpfr_zero_p (op.mpfr_srcptr()) != 0 ); } inline bool isint (const mpreal& op){ return (mpfr_integer_p(op.mpfr_srcptr()) != 0 ); } #if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) inline bool isregular(const mpreal& op){ return (mpfr_regular_p(op.mpfr_srcptr()));} #endif ////////////////////////////////////////////////////////////////////////// // Type Converters inline bool mpreal::toBool ( ) const { return mpfr_zero_p (mpfr_srcptr()) == 0; } inline long mpreal::toLong (mp_rnd_t mode) const { return mpfr_get_si (mpfr_srcptr(), mode); } inline unsigned long mpreal::toULong (mp_rnd_t mode) const { return mpfr_get_ui (mpfr_srcptr(), mode); } inline float mpreal::toFloat (mp_rnd_t mode) const { return mpfr_get_flt(mpfr_srcptr(), mode); } inline double mpreal::toDouble (mp_rnd_t mode) const { return mpfr_get_d (mpfr_srcptr(), mode); } inline long double mpreal::toLDouble(mp_rnd_t mode) const { return mpfr_get_ld (mpfr_srcptr(), mode); } inline long long mpreal::toLLong (mp_rnd_t mode) const { return mpfr_get_sj (mpfr_srcptr(), mode); } inline unsigned long long mpreal::toULLong (mp_rnd_t mode) const { return mpfr_get_uj (mpfr_srcptr(), mode); } inline ::mpfr_ptr mpreal::mpfr_ptr() { return mp; } inline ::mpfr_srcptr mpreal::mpfr_ptr() const { return mp; } inline ::mpfr_srcptr mpreal::mpfr_srcptr() const { return mp; } template inline std::string toString(T t, std::ios_base & (*f)(std::ios_base&)) { std::ostringstream oss; oss << f << t; return oss.str(); } #if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) inline std::string mpreal::toString(const std::string& format) const { char *s = NULL; std::string out; if( !format.empty() ) { if(!(mpfr_asprintf(&s, format.c_str(), mpfr_srcptr()) < 0)) { out = std::string(s); mpfr_free_str(s); } } return out; } #endif inline std::string mpreal::toString(int n, int b, mp_rnd_t mode) const { // TODO: Add extended format specification (f, e, rounding mode) as it done in output operator (void)b; (void)mode; #if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) std::ostringstream format; int digits = (n >= 0) ? n : 1 + bits2digits(mpfr_get_prec(mpfr_srcptr())); format << "%." << digits << "RNg"; return toString(format.str()); #else char *s, *ns = NULL; size_t slen, nslen; mp_exp_t exp; std::string out; if(mpfr_inf_p(mp)) { if(mpfr_sgn(mp)>0) return "+Inf"; else return "-Inf"; } if(mpfr_zero_p(mp)) return "0"; if(mpfr_nan_p(mp)) return "NaN"; s = mpfr_get_str(NULL, &exp, b, 0, mp, mode); ns = mpfr_get_str(NULL, &exp, b, (std::max)(0,n), mp, mode); if(s!=NULL && ns!=NULL) { slen = strlen(s); nslen = strlen(ns); if(nslen<=slen) { mpfr_free_str(s); s = ns; slen = nslen; } else { mpfr_free_str(ns); } // Make human eye-friendly formatting if possible if (exp>0 && static_cast(exp)s+exp) ptr--; if(ptr==s+exp) out = std::string(s,exp+1); else out = std::string(s,exp+1)+'.'+std::string(s+exp+1,ptr-(s+exp+1)+1); //out = string(s,exp+1)+'.'+string(s+exp+1); } else { // Remove zeros starting from right end char* ptr = s+slen-1; while (*ptr=='0' && ptr>s+exp-1) ptr--; if(ptr==s+exp-1) out = std::string(s,exp); else out = std::string(s,exp)+'.'+std::string(s+exp,ptr-(s+exp)+1); //out = string(s,exp)+'.'+string(s+exp); } }else{ // exp<0 || exp>slen if(s[0]=='-') { // Remove zeros starting from right end char* ptr = s+slen-1; while (*ptr=='0' && ptr>s+1) ptr--; if(ptr==s+1) out = std::string(s,2); else out = std::string(s,2)+'.'+std::string(s+2,ptr-(s+2)+1); //out = string(s,2)+'.'+string(s+2); } else { // Remove zeros starting from right end char* ptr = s+slen-1; while (*ptr=='0' && ptr>s) ptr--; if(ptr==s) out = std::string(s,1); else out = std::string(s,1)+'.'+std::string(s+1,ptr-(s+1)+1); //out = string(s,1)+'.'+string(s+1); } // Make final string if(--exp) { if(exp>0) out += "e+"+mpfr::toString(exp,std::dec); else out += "e"+mpfr::toString(exp,std::dec); } } mpfr_free_str(s); return out; }else{ return "conversion error!"; } #endif } ////////////////////////////////////////////////////////////////////////// // I/O inline std::ostream& mpreal::output(std::ostream& os) const { std::ostringstream format; const std::ios::fmtflags flags = os.flags(); format << ((flags & std::ios::showpos) ? "%+" : "%"); if (os.precision() >= 0) format << '.' << os.precision() << "R*" << ((flags & std::ios::floatfield) == std::ios::fixed ? 'f' : (flags & std::ios::floatfield) == std::ios::scientific ? 'e' : 'g'); else format << "R*e"; char *s = NULL; if(!(mpfr_asprintf(&s, format.str().c_str(), mpfr::mpreal::get_default_rnd(), mpfr_srcptr()) < 0)) { os << std::string(s); mpfr_free_str(s); } return os; } inline std::ostream& operator<<(std::ostream& os, const mpreal& v) { return v.output(os); } inline std::istream& operator>>(std::istream &is, mpreal& v) { // TODO: use cout::hexfloat and other flags to setup base std::string tmp; is >> tmp; mpfr_set_str(v.mpfr_ptr(), tmp.c_str(), 10, mpreal::get_default_rnd()); return is; } ////////////////////////////////////////////////////////////////////////// // Bits - decimal digits relation // bits = ceil(digits*log[2](10)) // digits = floor(bits*log[10](2)) inline mp_prec_t digits2bits(int d) { const double LOG2_10 = 3.3219280948873624; return mp_prec_t(std::ceil( d * LOG2_10 )); } inline int bits2digits(mp_prec_t b) { const double LOG10_2 = 0.30102999566398119; return int(std::floor( b * LOG10_2 )); } ////////////////////////////////////////////////////////////////////////// // Set/Get number properties inline int sgn(const mpreal& op) { return mpfr_sgn(op.mpfr_srcptr()); } inline mpreal& mpreal::setSign(int sign, mp_rnd_t RoundingMode) { mpfr_setsign(mpfr_ptr(), mpfr_srcptr(), (sign < 0 ? 1 : 0), RoundingMode); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline int mpreal::getPrecision() const { return int(mpfr_get_prec(mpfr_srcptr())); } inline mpreal& mpreal::setPrecision(int Precision, mp_rnd_t RoundingMode) { mpfr_prec_round(mpfr_ptr(), Precision, RoundingMode); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::setInf(int sign) { mpfr_set_inf(mpfr_ptr(), sign); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::setNan() { mpfr_set_nan(mpfr_ptr()); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mpreal& mpreal::setZero(int sign) { #if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) mpfr_set_zero(mpfr_ptr(), sign); #else mpfr_set_si(mpfr_ptr(), 0, (mpfr_get_default_rounding_mode)()); setSign(sign); #endif MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } inline mp_prec_t mpreal::get_prec() const { return mpfr_get_prec(mpfr_srcptr()); } inline void mpreal::set_prec(mp_prec_t prec, mp_rnd_t rnd_mode) { mpfr_prec_round(mpfr_ptr(),prec,rnd_mode); MPREAL_MSVC_DEBUGVIEW_CODE; } inline mp_exp_t mpreal::get_exp () { return mpfr_get_exp(mpfr_srcptr()); } inline int mpreal::set_exp (mp_exp_t e) { int x = mpfr_set_exp(mpfr_ptr(), e); MPREAL_MSVC_DEBUGVIEW_CODE; return x; } inline const mpreal frexp(const mpreal& v, mp_exp_t* exp) { mpreal x(v); *exp = x.get_exp(); x.set_exp(0); return x; } inline const mpreal ldexp(const mpreal& v, mp_exp_t exp) { mpreal x(v); // rounding is not important since we are just increasing the exponent (= exact operation) mpfr_mul_2si(x.mpfr_ptr(), x.mpfr_srcptr(), exp, mpreal::get_default_rnd()); return x; } inline const mpreal scalbn(const mpreal& v, mp_exp_t exp) { return ldexp(v, exp); } inline mpreal machine_epsilon(mp_prec_t prec) { /* the smallest eps such that 1 + eps != 1 */ return machine_epsilon(mpreal(1, prec)); } inline mpreal machine_epsilon(const mpreal& x) { /* the smallest eps such that x + eps != x */ if( x < 0) { return nextabove(-x) + x; }else{ return nextabove( x) - x; } } // minval is 'safe' meaning 1 / minval does not overflow inline mpreal minval(mp_prec_t prec) { /* min = 1/2 * 2^emin = 2^(emin - 1) */ return mpreal(1, prec) << mpreal::get_emin()-1; } // maxval is 'safe' meaning 1 / maxval does not underflow inline mpreal maxval(mp_prec_t prec) { /* max = (1 - eps) * 2^emax, eps is machine epsilon */ return (mpreal(1, prec) - machine_epsilon(prec)) << mpreal::get_emax(); } inline bool isEqualUlps(const mpreal& a, const mpreal& b, int maxUlps) { return abs(a - b) <= machine_epsilon((max)(abs(a), abs(b))) * maxUlps; } inline bool isEqualFuzzy(const mpreal& a, const mpreal& b, const mpreal& eps) { return abs(a - b) <= eps; } inline bool isEqualFuzzy(const mpreal& a, const mpreal& b) { return isEqualFuzzy(a, b, machine_epsilon((max)(1, (min)(abs(a), abs(b))))); } ////////////////////////////////////////////////////////////////////////// // C++11 sign functions. inline mpreal copysign(const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) { mpreal rop(0, mpfr_get_prec(x.mpfr_ptr())); mpfr_setsign(rop.mpfr_ptr(), x.mpfr_srcptr(), mpfr_signbit(y.mpfr_srcptr()), rnd_mode); return rop; } inline bool signbit(const mpreal& x) { return mpfr_signbit(x.mpfr_srcptr()); } inline const mpreal modf(const mpreal& v, mpreal& n) { mpreal f(v); // rounding is not important since we are using the same number mpfr_frac (f.mpfr_ptr(),f.mpfr_srcptr(),mpreal::get_default_rnd()); mpfr_trunc(n.mpfr_ptr(),v.mpfr_srcptr()); return f; } inline int mpreal::check_range (int t, mp_rnd_t rnd_mode) { return mpfr_check_range(mpfr_ptr(),t,rnd_mode); } inline int mpreal::subnormalize (int t,mp_rnd_t rnd_mode) { int r = mpfr_subnormalize(mpfr_ptr(),t,rnd_mode); MPREAL_MSVC_DEBUGVIEW_CODE; return r; } inline mp_exp_t mpreal::get_emin (void) { return mpfr_get_emin(); } inline int mpreal::set_emin (mp_exp_t exp) { return mpfr_set_emin(exp); } inline mp_exp_t mpreal::get_emax (void) { return mpfr_get_emax(); } inline int mpreal::set_emax (mp_exp_t exp) { return mpfr_set_emax(exp); } inline mp_exp_t mpreal::get_emin_min (void) { return mpfr_get_emin_min(); } inline mp_exp_t mpreal::get_emin_max (void) { return mpfr_get_emin_max(); } inline mp_exp_t mpreal::get_emax_min (void) { return mpfr_get_emax_min(); } inline mp_exp_t mpreal::get_emax_max (void) { return mpfr_get_emax_max(); } ////////////////////////////////////////////////////////////////////////// // Mathematical Functions ////////////////////////////////////////////////////////////////////////// #define MPREAL_UNARY_MATH_FUNCTION_BODY(f) \ mpreal y(0, mpfr_get_prec(x.mpfr_srcptr())); \ mpfr_##f(y.mpfr_ptr(), x.mpfr_srcptr(), r); \ return y; inline const mpreal sqr (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(sqr ); } inline const mpreal sqrt (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(sqrt); } inline const mpreal sqrt(const unsigned long int x, mp_rnd_t r) { mpreal y; mpfr_sqrt_ui(y.mpfr_ptr(), x, r); return y; } inline const mpreal sqrt(const unsigned int v, mp_rnd_t rnd_mode) { return sqrt(static_cast(v),rnd_mode); } inline const mpreal sqrt(const long int v, mp_rnd_t rnd_mode) { if (v>=0) return sqrt(static_cast(v),rnd_mode); else return mpreal().setNan(); // NaN } inline const mpreal sqrt(const int v, mp_rnd_t rnd_mode) { if (v>=0) return sqrt(static_cast(v),rnd_mode); else return mpreal().setNan(); // NaN } inline const mpreal root(const mpreal& x, unsigned long int k, mp_rnd_t r = mpreal::get_default_rnd()) { mpreal y(0, mpfr_get_prec(x.mpfr_srcptr())); mpfr_root(y.mpfr_ptr(), x.mpfr_srcptr(), k, r); return y; } inline const mpreal dim(const mpreal& a, const mpreal& b, mp_rnd_t r = mpreal::get_default_rnd()) { mpreal y(0, mpfr_get_prec(a.mpfr_srcptr())); mpfr_dim(y.mpfr_ptr(), a.mpfr_srcptr(), b.mpfr_srcptr(), r); return y; } inline int cmpabs(const mpreal& a,const mpreal& b) { return mpfr_cmpabs(a.mpfr_ptr(), b.mpfr_srcptr()); } inline int sin_cos(mpreal& s, mpreal& c, const mpreal& v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) { return mpfr_sin_cos(s.mpfr_ptr(), c.mpfr_ptr(), v.mpfr_srcptr(), rnd_mode); } inline const mpreal sqrt (const long double v, mp_rnd_t rnd_mode) { return sqrt(mpreal(v),rnd_mode); } inline const mpreal sqrt (const double v, mp_rnd_t rnd_mode) { return sqrt(mpreal(v),rnd_mode); } inline const mpreal cbrt (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(cbrt ); } inline const mpreal fabs (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(abs ); } inline const mpreal abs (const mpreal& x, mp_rnd_t r) { MPREAL_UNARY_MATH_FUNCTION_BODY(abs ); } inline const mpreal log (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(log ); } inline const mpreal log2 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(log2 ); } inline const mpreal log10 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(log10); } inline const mpreal exp (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(exp ); } inline const mpreal exp2 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(exp2 ); } inline const mpreal exp10 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(exp10); } inline const mpreal cos (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(cos ); } inline const mpreal sin (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(sin ); } inline const mpreal tan (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(tan ); } inline const mpreal sec (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(sec ); } inline const mpreal csc (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(csc ); } inline const mpreal cot (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(cot ); } inline const mpreal acos (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(acos ); } inline const mpreal asin (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(asin ); } inline const mpreal atan (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(atan ); } inline const mpreal logb (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { return log2 (abs(x),r); } inline const mpreal acot (const mpreal& v, mp_rnd_t r = mpreal::get_default_rnd()) { return atan (1/v, r); } inline const mpreal asec (const mpreal& v, mp_rnd_t r = mpreal::get_default_rnd()) { return acos (1/v, r); } inline const mpreal acsc (const mpreal& v, mp_rnd_t r = mpreal::get_default_rnd()) { return asin (1/v, r); } inline const mpreal acoth (const mpreal& v, mp_rnd_t r = mpreal::get_default_rnd()) { return atanh(1/v, r); } inline const mpreal asech (const mpreal& v, mp_rnd_t r = mpreal::get_default_rnd()) { return acosh(1/v, r); } inline const mpreal acsch (const mpreal& v, mp_rnd_t r = mpreal::get_default_rnd()) { return asinh(1/v, r); } inline const mpreal cosh (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(cosh ); } inline const mpreal sinh (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(sinh ); } inline const mpreal tanh (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(tanh ); } inline const mpreal sech (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(sech ); } inline const mpreal csch (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(csch ); } inline const mpreal coth (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(coth ); } inline const mpreal acosh (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(acosh); } inline const mpreal asinh (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(asinh); } inline const mpreal atanh (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(atanh); } inline const mpreal log1p (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(log1p ); } inline const mpreal expm1 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(expm1 ); } inline const mpreal eint (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(eint ); } inline const mpreal gamma (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(gamma ); } inline const mpreal tgamma (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(gamma ); } inline const mpreal lngamma (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(lngamma); } inline const mpreal zeta (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(zeta ); } inline const mpreal erf (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(erf ); } inline const mpreal erfc (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(erfc ); } inline const mpreal besselj0(const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(j0 ); } inline const mpreal besselj1(const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(j1 ); } inline const mpreal bessely0(const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(y0 ); } inline const mpreal bessely1(const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(y1 ); } inline const mpreal atan2 (const mpreal& y, const mpreal& x, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) { mpreal a(0,(std::max)(y.getPrecision(), x.getPrecision())); mpfr_atan2(a.mpfr_ptr(), y.mpfr_srcptr(), x.mpfr_srcptr(), rnd_mode); return a; } inline const mpreal hypot (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) { mpreal a(0,(std::max)(y.getPrecision(), x.getPrecision())); mpfr_hypot(a.mpfr_ptr(), x.mpfr_srcptr(), y.mpfr_srcptr(), rnd_mode); return a; } inline const mpreal remainder (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) { mpreal a(0,(std::max)(y.getPrecision(), x.getPrecision())); mpfr_remainder(a.mpfr_ptr(), x.mpfr_srcptr(), y.mpfr_srcptr(), rnd_mode); return a; } inline const mpreal remquo (long* q, const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) { mpreal a(0,(std::max)(y.getPrecision(), x.getPrecision())); mpfr_remquo(a.mpfr_ptr(),q, x.mpfr_srcptr(), y.mpfr_srcptr(), rnd_mode); return a; } inline const mpreal fac_ui (unsigned long int v, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t rnd_mode = mpreal::get_default_rnd()) { mpreal x(0, prec); mpfr_fac_ui(x.mpfr_ptr(),v,rnd_mode); return x; } inline const mpreal lgamma (const mpreal& v, int *signp = 0, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) { mpreal x(v); int tsignp; if(signp) mpfr_lgamma(x.mpfr_ptr(), signp,v.mpfr_srcptr(),rnd_mode); else mpfr_lgamma(x.mpfr_ptr(),&tsignp,v.mpfr_srcptr(),rnd_mode); return x; } inline const mpreal besseljn (long n, const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { mpreal y(0, x.getPrecision()); mpfr_jn(y.mpfr_ptr(), n, x.mpfr_srcptr(), r); return y; } inline const mpreal besselyn (long n, const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { mpreal y(0, x.getPrecision()); mpfr_yn(y.mpfr_ptr(), n, x.mpfr_srcptr(), r); return y; } inline const mpreal fma (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) { mpreal a; mp_prec_t p1, p2, p3; p1 = v1.get_prec(); p2 = v2.get_prec(); p3 = v3.get_prec(); a.set_prec(p3>p2?(p3>p1?p3:p1):(p2>p1?p2:p1)); mpfr_fma(a.mp,v1.mp,v2.mp,v3.mp,rnd_mode); return a; } inline const mpreal fms (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) { mpreal a; mp_prec_t p1, p2, p3; p1 = v1.get_prec(); p2 = v2.get_prec(); p3 = v3.get_prec(); a.set_prec(p3>p2?(p3>p1?p3:p1):(p2>p1?p2:p1)); mpfr_fms(a.mp,v1.mp,v2.mp,v3.mp,rnd_mode); return a; } inline const mpreal agm (const mpreal& v1, const mpreal& v2, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) { mpreal a; mp_prec_t p1, p2; p1 = v1.get_prec(); p2 = v2.get_prec(); a.set_prec(p1>p2?p1:p2); mpfr_agm(a.mp, v1.mp, v2.mp, rnd_mode); return a; } inline const mpreal sum (const mpreal tab[], const unsigned long int n, int& status, mp_rnd_t mode = mpreal::get_default_rnd()) { mpfr_srcptr *p = new mpfr_srcptr[n]; for (unsigned long int i = 0; i < n; i++) p[i] = tab[i].mpfr_srcptr(); mpreal x; status = mpfr_sum(x.mpfr_ptr(), (mpfr_ptr*)p, n, mode); delete [] p; return x; } ////////////////////////////////////////////////////////////////////////// // MPFR 2.4.0 Specifics #if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) inline int sinh_cosh(mpreal& s, mpreal& c, const mpreal& v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) { return mpfr_sinh_cosh(s.mp,c.mp,v.mp,rnd_mode); } inline const mpreal li2 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(li2); } inline const mpreal rem (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) { /* R = rem(X,Y) if Y != 0, returns X - n * Y where n = trunc(X/Y). */ return fmod(x, y, rnd_mode); } inline const mpreal mod (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) { (void)rnd_mode; /* m = mod(x,y) if y != 0, returns x - n*y where n = floor(x/y) The following are true by convention: - mod(x,0) is x - mod(x,x) is 0 - mod(x,y) for x != y and y != 0 has the same sign as y. */ if(iszero(y)) return x; if(x == y) return 0; mpreal m = x - floor(x / y) * y; m.setSign(sgn(y)); // make sure result has the same sign as Y return m; } inline const mpreal fmod (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) { mpreal a; mp_prec_t yp, xp; yp = y.get_prec(); xp = x.get_prec(); a.set_prec(yp>xp?yp:xp); mpfr_fmod(a.mp, x.mp, y.mp, rnd_mode); return a; } inline const mpreal rec_sqrt(const mpreal& v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) { mpreal x(v); mpfr_rec_sqrt(x.mp,v.mp,rnd_mode); return x; } #endif // MPFR 2.4.0 Specifics ////////////////////////////////////////////////////////////////////////// // MPFR 3.0.0 Specifics #if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) inline const mpreal digamma (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(digamma); } inline const mpreal ai (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(ai); } #endif // MPFR 3.0.0 Specifics ////////////////////////////////////////////////////////////////////////// // Constants inline const mpreal const_log2 (mp_prec_t p = mpreal::get_default_prec(), mp_rnd_t r = mpreal::get_default_rnd()) { mpreal x(0, p); mpfr_const_log2(x.mpfr_ptr(), r); return x; } inline const mpreal const_pi (mp_prec_t p = mpreal::get_default_prec(), mp_rnd_t r = mpreal::get_default_rnd()) { mpreal x(0, p); mpfr_const_pi(x.mpfr_ptr(), r); return x; } inline const mpreal const_euler (mp_prec_t p = mpreal::get_default_prec(), mp_rnd_t r = mpreal::get_default_rnd()) { mpreal x(0, p); mpfr_const_euler(x.mpfr_ptr(), r); return x; } inline const mpreal const_catalan (mp_prec_t p = mpreal::get_default_prec(), mp_rnd_t r = mpreal::get_default_rnd()) { mpreal x(0, p); mpfr_const_catalan(x.mpfr_ptr(), r); return x; } inline const mpreal const_infinity (int sign = 1, mp_prec_t p = mpreal::get_default_prec()) { mpreal x(0, p); mpfr_set_inf(x.mpfr_ptr(), sign); return x; } ////////////////////////////////////////////////////////////////////////// // Integer Related Functions inline const mpreal ceil(const mpreal& v) { mpreal x(v); mpfr_ceil(x.mp,v.mp); return x; } inline const mpreal floor(const mpreal& v) { mpreal x(v); mpfr_floor(x.mp,v.mp); return x; } inline const mpreal round(const mpreal& v) { mpreal x(v); mpfr_round(x.mp,v.mp); return x; } inline const mpreal trunc(const mpreal& v) { mpreal x(v); mpfr_trunc(x.mp,v.mp); return x; } inline const mpreal rint (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(rint ); } inline const mpreal rint_ceil (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(rint_ceil ); } inline const mpreal rint_floor (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(rint_floor); } inline const mpreal rint_round (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(rint_round); } inline const mpreal rint_trunc (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(rint_trunc); } inline const mpreal frac (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(frac ); } ////////////////////////////////////////////////////////////////////////// // Miscellaneous Functions inline void swap (mpreal& a, mpreal& b) { mpfr_swap(a.mp,b.mp); } inline const mpreal (max)(const mpreal& x, const mpreal& y){ return (x>y?x:y); } inline const mpreal (min)(const mpreal& x, const mpreal& y){ return (x= MPFR_VERSION_NUM(3,0,0)) inline const mpreal urandom (gmp_randstate_t& state, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) { mpreal x; mpfr_urandom(x.mpfr_ptr(), state, rnd_mode); return x; } #endif #if (MPFR_VERSION <= MPFR_VERSION_NUM(2,4,2)) inline const mpreal random2 (mp_size_t size, mp_exp_t exp) { mpreal x; mpfr_random2(x.mpfr_ptr(),size,exp); return x; } #endif // Uniformly distributed random number generation // a = random(seed); <- initialization & first random number generation // a = random(); <- next random numbers generation // seed != 0 inline const mpreal random(unsigned int seed = 0) { #if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) static gmp_randstate_t state; static bool initialize = true; if(initialize) { gmp_randinit_default(state); gmp_randseed_ui(state,0); initialize = false; } if(seed != 0) gmp_randseed_ui(state,seed); return mpfr::urandom(state); #else if(seed != 0) std::srand(seed); return mpfr::mpreal(std::rand()/(double)RAND_MAX); #endif } #if (MPFR_VERSION >= MPFR_VERSION_NUM(3,1,0)) inline const mpreal grandom (gmp_randstate_t& state, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) { mpreal x; mpfr_grandom(x.mpfr_ptr(), NULL, state, rnd_mode); return x; } inline const mpreal grandom(unsigned int seed = 0) { static gmp_randstate_t state; static bool initialize = true; if(initialize) { gmp_randinit_default(state); gmp_randseed_ui(state,0); initialize = false; } if(seed != 0) gmp_randseed_ui(state,seed); return mpfr::grandom(state); } #endif ////////////////////////////////////////////////////////////////////////// // Set/Get global properties inline void mpreal::set_default_prec(mp_prec_t prec) { mpfr_set_default_prec(prec); } inline void mpreal::set_default_rnd(mp_rnd_t rnd_mode) { mpfr_set_default_rounding_mode(rnd_mode); } inline bool mpreal::fits_in_bits(double x, int n) { int i; double t; return IsInf(x) || (std::modf ( std::ldexp ( std::frexp ( x, &i ), n ), &t ) == 0.0); } inline const mpreal pow(const mpreal& a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) { mpreal x(a); mpfr_pow(x.mp,x.mp,b.mp,rnd_mode); return x; } inline const mpreal pow(const mpreal& a, const mpz_t b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) { mpreal x(a); mpfr_pow_z(x.mp,x.mp,b,rnd_mode); return x; } inline const mpreal pow(const mpreal& a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) { mpreal x(a); mpfr_pow_ui(x.mp,x.mp,b,rnd_mode); return x; } inline const mpreal pow(const mpreal& a, const unsigned int b, mp_rnd_t rnd_mode) { return pow(a,static_cast(b),rnd_mode); } inline const mpreal pow(const mpreal& a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) { mpreal x(a); mpfr_pow_si(x.mp,x.mp,b,rnd_mode); return x; } inline const mpreal pow(const mpreal& a, const int b, mp_rnd_t rnd_mode) { return pow(a,static_cast(b),rnd_mode); } inline const mpreal pow(const mpreal& a, const long double b, mp_rnd_t rnd_mode) { return pow(a,mpreal(b),rnd_mode); } inline const mpreal pow(const mpreal& a, const double b, mp_rnd_t rnd_mode) { return pow(a,mpreal(b),rnd_mode); } inline const mpreal pow(const unsigned long int a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) { mpreal x(a); mpfr_ui_pow(x.mp,a,b.mp,rnd_mode); return x; } inline const mpreal pow(const unsigned int a, const mpreal& b, mp_rnd_t rnd_mode) { return pow(static_cast(a),b,rnd_mode); } inline const mpreal pow(const long int a, const mpreal& b, mp_rnd_t rnd_mode) { if (a>=0) return pow(static_cast(a),b,rnd_mode); else return pow(mpreal(a),b,rnd_mode); } inline const mpreal pow(const int a, const mpreal& b, mp_rnd_t rnd_mode) { if (a>=0) return pow(static_cast(a),b,rnd_mode); else return pow(mpreal(a),b,rnd_mode); } inline const mpreal pow(const long double a, const mpreal& b, mp_rnd_t rnd_mode) { return pow(mpreal(a),b,rnd_mode); } inline const mpreal pow(const double a, const mpreal& b, mp_rnd_t rnd_mode) { return pow(mpreal(a),b,rnd_mode); } // pow unsigned long int inline const mpreal pow(const unsigned long int a, const unsigned long int b, mp_rnd_t rnd_mode) { mpreal x(a); mpfr_ui_pow_ui(x.mp,a,b,rnd_mode); return x; } inline const mpreal pow(const unsigned long int a, const unsigned int b, mp_rnd_t rnd_mode) { return pow(a,static_cast(b),rnd_mode); //mpfr_ui_pow_ui } inline const mpreal pow(const unsigned long int a, const long int b, mp_rnd_t rnd_mode) { if(b>0) return pow(a,static_cast(b),rnd_mode); //mpfr_ui_pow_ui else return pow(a,mpreal(b),rnd_mode); //mpfr_ui_pow } inline const mpreal pow(const unsigned long int a, const int b, mp_rnd_t rnd_mode) { if(b>0) return pow(a,static_cast(b),rnd_mode); //mpfr_ui_pow_ui else return pow(a,mpreal(b),rnd_mode); //mpfr_ui_pow } inline const mpreal pow(const unsigned long int a, const long double b, mp_rnd_t rnd_mode) { return pow(a,mpreal(b),rnd_mode); //mpfr_ui_pow } inline const mpreal pow(const unsigned long int a, const double b, mp_rnd_t rnd_mode) { return pow(a,mpreal(b),rnd_mode); //mpfr_ui_pow } // pow unsigned int inline const mpreal pow(const unsigned int a, const unsigned long int b, mp_rnd_t rnd_mode) { return pow(static_cast(a),b,rnd_mode); //mpfr_ui_pow_ui } inline const mpreal pow(const unsigned int a, const unsigned int b, mp_rnd_t rnd_mode) { return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui } inline const mpreal pow(const unsigned int a, const long int b, mp_rnd_t rnd_mode) { if(b>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui else return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow } inline const mpreal pow(const unsigned int a, const int b, mp_rnd_t rnd_mode) { if(b>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui else return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow } inline const mpreal pow(const unsigned int a, const long double b, mp_rnd_t rnd_mode) { return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow } inline const mpreal pow(const unsigned int a, const double b, mp_rnd_t rnd_mode) { return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow } // pow long int inline const mpreal pow(const long int a, const unsigned long int b, mp_rnd_t rnd_mode) { if (a>0) return pow(static_cast(a),b,rnd_mode); //mpfr_ui_pow_ui else return pow(mpreal(a),b,rnd_mode); //mpfr_pow_ui } inline const mpreal pow(const long int a, const unsigned int b, mp_rnd_t rnd_mode) { if (a>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui else return pow(mpreal(a),static_cast(b),rnd_mode); //mpfr_pow_ui } inline const mpreal pow(const long int a, const long int b, mp_rnd_t rnd_mode) { if (a>0) { if(b>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui else return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow }else{ return pow(mpreal(a),b,rnd_mode); // mpfr_pow_si } } inline const mpreal pow(const long int a, const int b, mp_rnd_t rnd_mode) { if (a>0) { if(b>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui else return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow }else{ return pow(mpreal(a),static_cast(b),rnd_mode); // mpfr_pow_si } } inline const mpreal pow(const long int a, const long double b, mp_rnd_t rnd_mode) { if (a>=0) return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow else return pow(mpreal(a),mpreal(b),rnd_mode); //mpfr_pow } inline const mpreal pow(const long int a, const double b, mp_rnd_t rnd_mode) { if (a>=0) return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow else return pow(mpreal(a),mpreal(b),rnd_mode); //mpfr_pow } // pow int inline const mpreal pow(const int a, const unsigned long int b, mp_rnd_t rnd_mode) { if (a>0) return pow(static_cast(a),b,rnd_mode); //mpfr_ui_pow_ui else return pow(mpreal(a),b,rnd_mode); //mpfr_pow_ui } inline const mpreal pow(const int a, const unsigned int b, mp_rnd_t rnd_mode) { if (a>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui else return pow(mpreal(a),static_cast(b),rnd_mode); //mpfr_pow_ui } inline const mpreal pow(const int a, const long int b, mp_rnd_t rnd_mode) { if (a>0) { if(b>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui else return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow }else{ return pow(mpreal(a),b,rnd_mode); // mpfr_pow_si } } inline const mpreal pow(const int a, const int b, mp_rnd_t rnd_mode) { if (a>0) { if(b>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui else return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow }else{ return pow(mpreal(a),static_cast(b),rnd_mode); // mpfr_pow_si } } inline const mpreal pow(const int a, const long double b, mp_rnd_t rnd_mode) { if (a>=0) return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow else return pow(mpreal(a),mpreal(b),rnd_mode); //mpfr_pow } inline const mpreal pow(const int a, const double b, mp_rnd_t rnd_mode) { if (a>=0) return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow else return pow(mpreal(a),mpreal(b),rnd_mode); //mpfr_pow } // pow long double inline const mpreal pow(const long double a, const long double b, mp_rnd_t rnd_mode) { return pow(mpreal(a),mpreal(b),rnd_mode); } inline const mpreal pow(const long double a, const unsigned long int b, mp_rnd_t rnd_mode) { return pow(mpreal(a),b,rnd_mode); //mpfr_pow_ui } inline const mpreal pow(const long double a, const unsigned int b, mp_rnd_t rnd_mode) { return pow(mpreal(a),static_cast(b),rnd_mode); //mpfr_pow_ui } inline const mpreal pow(const long double a, const long int b, mp_rnd_t rnd_mode) { return pow(mpreal(a),b,rnd_mode); // mpfr_pow_si } inline const mpreal pow(const long double a, const int b, mp_rnd_t rnd_mode) { return pow(mpreal(a),static_cast(b),rnd_mode); // mpfr_pow_si } inline const mpreal pow(const double a, const double b, mp_rnd_t rnd_mode) { return pow(mpreal(a),mpreal(b),rnd_mode); } inline const mpreal pow(const double a, const unsigned long int b, mp_rnd_t rnd_mode) { return pow(mpreal(a),b,rnd_mode); // mpfr_pow_ui } inline const mpreal pow(const double a, const unsigned int b, mp_rnd_t rnd_mode) { return pow(mpreal(a),static_cast(b),rnd_mode); // mpfr_pow_ui } inline const mpreal pow(const double a, const long int b, mp_rnd_t rnd_mode) { return pow(mpreal(a),b,rnd_mode); // mpfr_pow_si } inline const mpreal pow(const double a, const int b, mp_rnd_t rnd_mode) { return pow(mpreal(a),static_cast(b),rnd_mode); // mpfr_pow_si } } // End of mpfr namespace // Explicit specialization of std::swap for mpreal numbers // Thus standard algorithms will use efficient version of swap (due to Koenig lookup) // Non-throwing swap C++ idiom: http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-throwing_swap namespace std { // we are allowed to extend namespace std with specializations only template <> inline void swap(mpfr::mpreal& x, mpfr::mpreal& y) noexcept { return mpfr::swap(x, y); } template<> class numeric_limits { public: static const bool is_specialized = true; static const bool is_signed = true; static const bool is_integer = false; static const bool is_exact = false; static const int radix = 2; static const bool has_infinity = true; static const bool has_quiet_NaN = true; static const bool has_signaling_NaN = true; static const bool is_iec559 = true; // = IEEE 754 static const bool is_bounded = true; static const bool is_modulo = false; static const bool traps = true; static const bool tinyness_before = true; static const float_denorm_style has_denorm = denorm_absent; inline static mpfr::mpreal (min) (mp_prec_t precision = mpfr::mpreal::get_default_prec()) { return mpfr::minval(precision); } inline static mpfr::mpreal (max) (mp_prec_t precision = mpfr::mpreal::get_default_prec()) { return mpfr::maxval(precision); } inline static mpfr::mpreal lowest (mp_prec_t precision = mpfr::mpreal::get_default_prec()) { return -mpfr::maxval(precision); } // Returns smallest eps such that 1 + eps != 1 (classic machine epsilon) inline static mpfr::mpreal epsilon(mp_prec_t precision = mpfr::mpreal::get_default_prec()) { return mpfr::machine_epsilon(precision); } // Returns smallest eps such that x + eps != x (relative machine epsilon) inline static mpfr::mpreal epsilon(const mpfr::mpreal& x) { return mpfr::machine_epsilon(x); } inline static mpfr::mpreal round_error(mp_prec_t precision = mpfr::mpreal::get_default_prec()) { mp_rnd_t r = mpfr::mpreal::get_default_rnd(); if(r == GMP_RNDN) return mpfr::mpreal(0.5, precision); else return mpfr::mpreal(1.0, precision); } inline static const mpfr::mpreal infinity() { return mpfr::const_infinity(); } inline static const mpfr::mpreal quiet_NaN() { return mpfr::mpreal().setNan(); } inline static const mpfr::mpreal signaling_NaN() { return mpfr::mpreal().setNan(); } inline static const mpfr::mpreal denorm_min() { return (min)(); } // Please note, exponent range is not fixed in MPFR static const int min_exponent = MPFR_EMIN_DEFAULT; static const int max_exponent = MPFR_EMAX_DEFAULT; MPREAL_PERMISSIVE_EXPR static const int min_exponent10 = (int) (MPFR_EMIN_DEFAULT * 0.3010299956639811); MPREAL_PERMISSIVE_EXPR static const int max_exponent10 = (int) (MPFR_EMAX_DEFAULT * 0.3010299956639811); #ifdef MPREAL_HAVE_DYNAMIC_STD_NUMERIC_LIMITS // Following members should be constant according to standard, but they can be variable in MPFR // So we define them as functions here. // // This is preferable way for std::numeric_limits specialization. // But it is incompatible with standard std::numeric_limits and might not work with other libraries, e.g. boost. // See below for compatible implementation. inline static float_round_style round_style() { mp_rnd_t r = mpfr::mpreal::get_default_rnd(); switch (r) { case GMP_RNDN: return round_to_nearest; case GMP_RNDZ: return round_toward_zero; case GMP_RNDU: return round_toward_infinity; case GMP_RNDD: return round_toward_neg_infinity; default: return round_indeterminate; } } inline static int digits() { return int(mpfr::mpreal::get_default_prec()); } inline static int digits(const mpfr::mpreal& x) { return x.getPrecision(); } inline static int digits10(mp_prec_t precision = mpfr::mpreal::get_default_prec()) { return mpfr::bits2digits(precision); } inline static int digits10(const mpfr::mpreal& x) { return mpfr::bits2digits(x.getPrecision()); } inline static int max_digits10(mp_prec_t precision = mpfr::mpreal::get_default_prec()) { return digits10(precision); } #else // Digits and round_style are NOT constants when it comes to mpreal. // If possible, please use functions digits() and round_style() defined above. // // These (default) values are preserved for compatibility with existing libraries, e.g. boost. // Change them accordingly to your application. // // For example, if you use 256 bits of precision uniformly in your program, then: // digits = 256 // digits10 = 77 // max_digits10 = 78 // // Approximate formula for decimal digits is: digits10 = floor(log10(2) * digits). See bits2digits() for more details. static const std::float_round_style round_style = round_to_nearest; static const int digits = 53; static const int digits10 = 15; static const int max_digits10 = 16; #endif }; } #ifdef _MSC_VER #pragma warning(pop) #else #pragma GCC diagnostic pop #endif #endif /* __MPREAL_H__ */ ================================================ FILE: external/tinyprocesslib/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2015-2016 Ole Christian Eidheim Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: external/tinyprocesslib/README.md ================================================ # tiny-process-library [![Build Status](https://travis-ci.org/eidheim/tiny-process-library.svg?branch=master)](https://travis-ci.org/eidheim/tiny-process-library) A small platform independent library making it simple to create and stop new processes in C++, as well as writing to stdin and reading from stdout and stderr of a new process. This library was created for, and is used by the C++ IDE project [juCi++](https://github.com/cppit/jucipp). ### Features * No external dependencies * Simple to use * Platform independent * Creating processes using executables is supported on all platforms * Creating processes using functions is only possible on Unix-like systems * Read separately from stout and stderr using anonymous functions * Write to stdin * Kill a running process (SIGTERM is supported on Unix-like systems) * Correctly closes file descriptors/handles ### Usage See [examples.cpp](https://github.com/eidheim/tiny-process-library/blob/master/examples.cpp). ### Get, compile and run #### Unix-like systems ```sh git clone http://github.com/eidheim/tiny-process-library cd tiny-process-library mkdir build cd build cmake .. make ./examples ``` #### Windows with MSYS2 (https://msys2.github.io/) ```sh git clone http://github.com/eidheim/tiny-process-library cd tiny-process-library mkdir build cd build cmake -G"MSYS Makefiles" .. make ./examples ``` ================================================ FILE: external/tinyprocesslib/process.cpp ================================================ #include "tinyprocess.h" namespace tinyproclib { Process::Process(const string_type &command, const string_type &path, std::function read_stdout, std::function read_stderr, bool open_stdin, size_t buffer_size): closed(true), read_stdout(read_stdout), read_stderr(read_stderr), open_stdin(open_stdin), buffer_size(buffer_size) { open(command, path); async_read(); } Process::~Process() { close_fds(); } Process::id_type Process::get_id() { return data.id; } bool Process::write(const std::string &data) { return write(data.c_str(), data.size()); } } ================================================ FILE: external/tinyprocesslib/process_os.cpp ================================================ #ifdef _WIN32 #include "process_win.inc" #else #include "process_unix.inc" #endif ================================================ FILE: external/tinyprocesslib/process_unix.inc ================================================ #include "tinyprocess.h" #include #include #include #include namespace tinyproclib { Process::Data::Data() : id(-1) { } Process::Process(std::function function, std::function read_stdout, std::function read_stderr, bool open_stdin, size_t buffer_size) : closed(true), read_stdout(read_stdout), read_stderr(read_stderr), open_stdin(open_stdin), buffer_size(buffer_size) { open(function); async_read(); } Process::id_type Process::open(std::function function) { if(open_stdin) stdin_fd = std::unique_ptr(new fd_type); if(read_stdout) stdout_fd = std::unique_ptr(new fd_type); if(read_stderr) stderr_fd = std::unique_ptr(new fd_type); int stdin_p[2]; int stdout_p[2]; int stderr_p[2]; if(stdin_fd && pipe(stdin_p) != 0) return -1; if(stdout_fd && pipe(stdout_p) != 0) { if(stdin_fd) { close(stdin_p[0]); close(stdin_p[1]); } return -1; } if(stderr_fd && pipe(stderr_p) != 0) { if(stdin_fd) { close(stdin_p[0]); close(stdin_p[1]); } if(stdout_fd) { close(stdout_p[0]); close(stdout_p[1]); } return -1; } id_type pid = fork(); if(pid < 0) { if(stdin_fd) { close(stdin_p[0]); close(stdin_p[1]); } if(stdout_fd) { close(stdout_p[0]); close(stdout_p[1]); } if(stderr_fd) { close(stderr_p[0]); close(stderr_p[1]); } return pid; } else if(pid == 0) { if(stdin_fd) dup2(stdin_p[0], 0); if(stdout_fd) dup2(stdout_p[1], 1); if(stderr_fd) dup2(stderr_p[1], 2); if(stdin_fd) { close(stdin_p[0]); close(stdin_p[1]); } if(stdout_fd) { close(stdout_p[0]); close(stdout_p[1]); } if(stderr_fd) { close(stderr_p[0]); close(stderr_p[1]); } // Based on http://stackoverflow.com/a/899533/3808293 int fd_max = sysconf(_SC_OPEN_MAX); for(int fd = 3; fd < fd_max; fd++) close(fd); setpgid(0, 0); // TODO: See here on how to emulate tty for colors: http://stackoverflow.com/questions/1401002/trick-an-application-into-thinking-its-stdin-is-interactive-not-a-pipe // TODO: One solution is: echo "command;exit"|script -q /dev/null if(function) function(); _exit(EXIT_FAILURE); } if(stdin_fd) close(stdin_p[0]); if(stdout_fd) close(stdout_p[1]); if(stderr_fd) close(stderr_p[1]); if(stdin_fd) *stdin_fd = stdin_p[1]; if(stdout_fd) *stdout_fd = stdout_p[0]; if(stderr_fd) *stderr_fd = stderr_p[0]; closed = false; data.id = pid; return pid; } Process::id_type Process::open(const std::string& command, const std::string& path) { return open([&command, &path] { if(!path.empty()) { auto path_escaped = path; size_t pos = 0; // Based on https://www.reddit.com/r/cpp/comments/3vpjqg/a_new_platform_independent_process_library_for_c11/cxsxyb7 while((pos = path_escaped.find('\'', pos)) != std::string::npos) { path_escaped.replace(pos, 1, "'\\''"); pos += 4; } execl("/bin/sh", "sh", "-c", ("cd '" + path_escaped + "' && " + command).c_str(), NULL); } else { execl("/bin/sh", "sh", "-c", command.c_str(), NULL); } }); } void Process::async_read() { if(data.id <= 0) return; if(stdout_fd) { stdout_thread = std::thread([this]() { auto buffer = std::unique_ptr(new char[buffer_size]); ssize_t n = 0; while((n = read(*stdout_fd, buffer.get(), buffer_size)) > 0) read_stdout(buffer.get(), static_cast(n)); }); } if(stderr_fd) { stderr_thread = std::thread([this]() { auto buffer = std::unique_ptr(new char[buffer_size]); ssize_t n = 0; while((n = read(*stderr_fd, buffer.get(), buffer_size)) > 0) read_stderr(buffer.get(), static_cast(n)); }); } } int Process::get_exit_status() { if(data.id <= 0) return -1; int exit_status; waitpid(data.id, &exit_status, 0); { std::lock_guard lock(close_mutex); closed = true; } close_fds(); if(exit_status >= 256) exit_status = exit_status >> 8; return exit_status; } void Process::close_fds() { if(stdout_thread.joinable()) stdout_thread.join(); if(stderr_thread.joinable()) stderr_thread.join(); if(stdin_fd) close_stdin(); if(stdout_fd) { if(data.id > 0) close(*stdout_fd); stdout_fd.reset(); } if(stderr_fd) { if(data.id > 0) close(*stderr_fd); stderr_fd.reset(); } } bool Process::write(const char* bytes, size_t n) { if(!open_stdin) return false; // throw std::invalid_argument("Can't write to an unopened stdin pipe. Please set open_stdin=true when constructing the process."); std::lock_guard lock(stdin_mutex); if(stdin_fd) { if(::write(*stdin_fd, bytes, n) >= 0) return true; else return false; } return false; } void Process::close_stdin() { std::lock_guard lock(stdin_mutex); if(stdin_fd) { if(data.id > 0) close(*stdin_fd); stdin_fd.reset(); } } void Process::kill(bool force) { std::lock_guard lock(close_mutex); if(data.id>0 && !closed) { if(force) ::kill(-data.id, SIGTERM); else ::kill(-data.id, SIGINT); } } void Process::kill(id_type id, bool force) { if(id <= 0) return; if(force) ::kill(-id, SIGTERM); else ::kill(-id, SIGINT); } } ================================================ FILE: external/tinyprocesslib/process_win.inc ================================================ #include "tinyprocess.h" #include #include #include #include namespace tinyproclib { Process::Data::Data(): id(0), handle(NULL) {} namespace { // Simple HANDLE wrapper to close it automatically from the destructor. class Handle { public: Handle() : handle(INVALID_HANDLE_VALUE) { } ~Handle() { close(); } void close() { if (handle != INVALID_HANDLE_VALUE) ::CloseHandle(handle); } HANDLE detach() { HANDLE old_handle = handle; handle = INVALID_HANDLE_VALUE; return old_handle; } operator HANDLE() const { return handle; } HANDLE* operator&() { return &handle; } private: HANDLE handle; }; //Based on the discussion thread: https://www.reddit.com/r/cpp/comments/3vpjqg/a_new_platform_independent_process_library_for_c11/cxq1wsj std::mutex create_process_mutex; } //Based on the example at https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx. Process::id_type Process::open(const string_type &command, const string_type &path) { if(open_stdin) stdin_fd=std::unique_ptr(new fd_type(NULL)); if(read_stdout) stdout_fd=std::unique_ptr(new fd_type(NULL)); if(read_stderr) stderr_fd=std::unique_ptr(new fd_type(NULL)); Handle stdin_rd_p; Handle stdin_wr_p; Handle stdout_rd_p; Handle stdout_wr_p; Handle stderr_rd_p; Handle stderr_wr_p; SECURITY_ATTRIBUTES security_attributes; security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES); security_attributes.bInheritHandle = TRUE; security_attributes.lpSecurityDescriptor = nullptr; std::lock_guard lock(create_process_mutex); if(stdin_fd) { if (!CreatePipe(&stdin_rd_p, &stdin_wr_p, &security_attributes, 0) || !SetHandleInformation(stdin_wr_p, HANDLE_FLAG_INHERIT, 0)) return 0; } if(stdout_fd) { if (!CreatePipe(&stdout_rd_p, &stdout_wr_p, &security_attributes, 0) || !SetHandleInformation(stdout_rd_p, HANDLE_FLAG_INHERIT, 0)) { return 0; } } if(stderr_fd) { if (!CreatePipe(&stderr_rd_p, &stderr_wr_p, &security_attributes, 0) || !SetHandleInformation(stderr_rd_p, HANDLE_FLAG_INHERIT, 0)) { return 0; } } PROCESS_INFORMATION process_info; STARTUPINFO startup_info; ZeroMemory(&process_info, sizeof(PROCESS_INFORMATION)); ZeroMemory(&startup_info, sizeof(STARTUPINFO)); startup_info.cb = sizeof(STARTUPINFO); startup_info.hStdInput = stdin_rd_p; startup_info.hStdOutput = stdout_wr_p; startup_info.hStdError = stderr_wr_p; if(stdin_fd || stdout_fd || stderr_fd) startup_info.dwFlags |= STARTF_USESTDHANDLES; string_type process_command=command; #ifdef MSYS_PROCESS_USE_SH size_t pos=0; while((pos=process_command.find('\\', pos))!=string_type::npos) { process_command.replace(pos, 1, "\\\\\\\\"); pos+=4; } pos=0; while((pos=process_command.find('\"', pos))!=string_type::npos) { process_command.replace(pos, 1, "\\\""); pos+=2; } process_command.insert(0, "sh -c \""); process_command+="\""; #endif BOOL bSuccess = CreateProcess(nullptr, process_command.empty()?nullptr:&process_command[0], nullptr, nullptr, TRUE, 0, nullptr, path.empty()?nullptr:path.c_str(), &startup_info, &process_info); if(!bSuccess) { CloseHandle(process_info.hProcess); CloseHandle(process_info.hThread); return 0; } else { CloseHandle(process_info.hThread); } if(stdin_fd) *stdin_fd=stdin_wr_p.detach(); if(stdout_fd) *stdout_fd=stdout_rd_p.detach(); if(stderr_fd) *stderr_fd=stderr_rd_p.detach(); closed=false; data.id=process_info.dwProcessId; data.handle=process_info.hProcess; return process_info.dwProcessId; } void Process::async_read() { if(data.id==0) return; if(stdout_fd) { stdout_thread=std::thread([this](){ DWORD n; std::unique_ptr buffer(new char[buffer_size]); for (;;) { BOOL bSuccess = ReadFile(*stdout_fd, static_cast(buffer.get()), static_cast(buffer_size), &n, nullptr); if(!bSuccess || n == 0) break; read_stdout(buffer.get(), static_cast(n)); } }); } if(stderr_fd) { stderr_thread=std::thread([this](){ DWORD n; std::unique_ptr buffer(new char[buffer_size]); for (;;) { BOOL bSuccess = ReadFile(*stderr_fd, static_cast(buffer.get()), static_cast(buffer_size), &n, nullptr); if(!bSuccess || n == 0) break; read_stderr(buffer.get(), static_cast(n)); } }); } } int Process::get_exit_status() { if(data.id==0) return -1; DWORD exit_status; WaitForSingleObject(data.handle, INFINITE); if(!GetExitCodeProcess(data.handle, &exit_status)) exit_status=(DWORD)-1; { std::lock_guard lock(close_mutex); CloseHandle(data.handle); closed=true; } close_fds(); return static_cast(exit_status); } void Process::close_fds() { if(stdout_thread.joinable()) stdout_thread.join(); if(stderr_thread.joinable()) stderr_thread.join(); if(stdin_fd) close_stdin(); if(stdout_fd) { if(*stdout_fd!=NULL) CloseHandle(*stdout_fd); stdout_fd.reset(); } if(stderr_fd) { if(*stderr_fd!=NULL) CloseHandle(*stderr_fd); stderr_fd.reset(); } } bool Process::write(const char *bytes, size_t n) { if(!open_stdin) throw std::invalid_argument("Can't write to an unopened stdin pipe. Please set open_stdin=true when constructing the process."); std::lock_guard lock(stdin_mutex); if(stdin_fd) { DWORD written; BOOL bSuccess=WriteFile(*stdin_fd, bytes, static_cast(n), &written, nullptr); if(!bSuccess || written==0) { return false; } else { return true; } } return false; } void Process::close_stdin() { std::lock_guard lock(stdin_mutex); if(stdin_fd) { if(*stdin_fd!=NULL) CloseHandle(*stdin_fd); stdin_fd.reset(); } } //Based on http://stackoverflow.com/a/1173396 void Process::kill(bool force) { std::lock_guard lock(close_mutex); if(data.id>0 && !closed) { HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if(snapshot) { PROCESSENTRY32 process; ZeroMemory(&process, sizeof(process)); process.dwSize = sizeof(process); if(Process32First(snapshot, &process)) { do { if(process.th32ParentProcessID==data.id) { HANDLE process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, process.th32ProcessID); if(process_handle) { TerminateProcess(process_handle, 2); CloseHandle(process_handle); } } } while (Process32Next(snapshot, &process)); } CloseHandle(snapshot); } TerminateProcess(data.handle, 2); } } //Based on http://stackoverflow.com/a/1173396 void Process::kill(id_type id, bool force) { if(id==0) return; HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if(snapshot) { PROCESSENTRY32 process; ZeroMemory(&process, sizeof(process)); process.dwSize = sizeof(process); if(Process32First(snapshot, &process)) { do { if(process.th32ParentProcessID==id) { HANDLE process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, process.th32ProcessID); if(process_handle) { TerminateProcess(process_handle, 2); CloseHandle(process_handle); } } } while (Process32Next(snapshot, &process)); } CloseHandle(snapshot); } HANDLE process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, id); if(process_handle) TerminateProcess(process_handle, 2); } } ================================================ FILE: external/tinyprocesslib/tinyprocess.h ================================================ #ifndef TINY_PROCESS_LIBRARY_HPP_ #define TINY_PROCESS_LIBRARY_HPP_ #include #include #include #include #include #include #ifndef _WIN32 #include #endif namespace tinyproclib { ///Platform independent class for creating processes class Process { public: #ifdef _WIN32 typedef unsigned long id_type; //Process id type typedef void *fd_type; //File descriptor type #ifdef UNICODE typedef std::wstring string_type; #else typedef std::string string_type; #endif #else typedef pid_t id_type; typedef int fd_type; typedef std::string string_type; #endif private: class Data { public: Data(); id_type id; #ifdef _WIN32 void *handle; #endif }; public: ///Note on Windows: it seems not possible to specify which pipes to redirect. ///Thus, at the moment, if read_stdout==nullptr, read_stderr==nullptr and open_stdin==false, ///the stdout, stderr and stdin are sent to the parent process instead. Process(const string_type &command, const string_type &path=string_type(), std::function read_stdout=nullptr, std::function read_stderr=nullptr, bool open_stdin=false, size_t buffer_size=131072); #ifndef _WIN32 /// Supported on Unix-like systems only. Process(std::function function, std::function read_stdout=nullptr, std::function read_stderr=nullptr, bool open_stdin=false, size_t buffer_size=131072); #endif ~Process(); ///Get the process id of the started process. id_type get_id(); ///Wait until process is finished, and return exit status. int get_exit_status(); ///Write to stdin. bool write(const char *bytes, size_t n); ///Write to stdin. Convenience function using write(const char *, size_t). bool write(const std::string &data); ///Close stdin. If the process takes parameters from stdin, use this to notify that all parameters have been sent. void close_stdin(); ///Kill the process. force=true is only supported on Unix-like systems. void kill(bool force=false); ///Kill a given process id. Use kill(bool force) instead if possible. force=true is only supported on Unix-like systems. static void kill(id_type id, bool force=false); private: Data data; bool closed; std::mutex close_mutex; std::function read_stdout; std::function read_stderr; std::thread stdout_thread, stderr_thread; bool open_stdin; std::mutex stdin_mutex; size_t buffer_size; std::unique_ptr stdout_fd, stderr_fd, stdin_fd; id_type open(const string_type &command, const string_type &path); #ifndef _WIN32 id_type open(std::function function); #endif void async_read(); void close_fds(); }; } #endif // TINY_PROCESS_LIBRARY_HPP_ ================================================ FILE: external/utf8rewind/LICENSE ================================================ Copyright (C) 2014-2015 Quinten Lansu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: external/utf8rewind/README.md ================================================ ## Introduction ## `utf8rewind` is a cross-platform and open source C library designed to extend the default string handling functions and add support for UTF-8 encoded text. ## Example ## ``` #!c #include "../include/utf8rewind.h" int main(int argc, char** argv) { const char* input = "Hello World!"; static const size_t output_size = 256; char output[output_size]; wchar_t output_wide[output_size]; const char* input_seek; size_t converted_size; int32_t errors; memset(output, 0, output_size * sizeof(char)); memset(output_wide, 0, output_size * sizeof(wchar_t)); /* Convert input to uppercase: "Hello World!" -> "HELLO WORLD!" */ converted_size = utf8toupper( input, strlen(input), output, output_size - 1, &errors); if (converted_size == 0 || errors != UTF8_ERR_NONE) { return -1; } /* Convert UTF-8 input to wide (UTF-16 or UTF-32) encoded text: "HELLO WORLD!" -> L"HELLO WORLD!" */ converted_size = utf8towide( output, strlen(output), output_wide, (output_size - 1) * sizeof(wchar_t), &errors); if (converted_size == 0 || errors != UTF8_ERR_NONE) { return -1; } /* Seek in input: Hello World!" -> "World!" */ input_seek = utf8seek(input, input, 6, SEEK_SET); return 0; } ``` ## Features ## * **Conversion to and from UTF-8** - `utf8rewind` provides functions for converting from and to wide, UTF-16 and UTF-32 encoded text. * **Case mapping** - The library also provides functionality for converting text to uppercase, lowercase and titlecase. * **Normalization** - With `utf8normalize`, you can normalize UTF-8 encoded text to NFC, NFD, NFKC or NFKD without converting it to UTF-32 first. * **Seeking** - Using `utf8seek`, you can seek forwards and backwards in UTF-8 encoded text. * **Cross-platform** - `utf8rewind` is written in plain C, which means it can be used on any platform with a compliant C compiler. Currently, Windows, Linux and Mac versions are available. * **Easy to integrate** - The library consists of only 13 public functions and requires no initialization. Any C or C++ project can add `utf8rewind` without breaking existing code. * **Simple bindings** - No structs are used in the public interface, only pointers. Even if you don't use C, if the language of your choice allows bindings to C functions (e.g. Python), you can benefit from integrating `utf8rewind` into your project. * **No heap allocations** - All allocations in `utf8rewind` happen on the stack. You provide the memory, without having to override `malloc`. This makes the library perfectly tailored to game engines, integrated systems and other performance-critical or memory-constrained projects. * **Safety** - Over 2300 automated unit and integration tests guarantee the safety and security of the library. ## Licensing ## This project is licensed under the MIT license, a full copy of which should have been provided with the project. ## Download ## [utf8rewind-1.2.1.zip (3.17 MB)](https://bitbucket.org/knight666/utf8rewind/downloads/utf8rewind-1.2.1.zip) ### Clone in Mercurial ### hg clone https://bitbucket.org/knight666/utf8rewind utf8rewind ## Building the project ## All supported platforms use [GYP](http://code.google.com/p/gyp/) to generate a solution. This generated solution can be used to compile the project and its dependencies. ### Building on Windows with Visual Studio ### You will need to have Visual Studio 2010 or above installed. Open a command window at the project's root. If you have multiple versions of Visual Studio installed, you must first specify the version you want to use: set GYP_MSVS_VERSION=2012 Use GYP to generate a solution: tools\gyp\gyp --depth utf8rewind.gyp Open the solution in Visual Studio. You can use the different build configurations to generate a static library. ### Building on Linux with GCC ### Open a command window at the project's root. Ensure you have all dependencies installed using your preferred package manager: sudo apt-get install gcc g++ gyp doxygen Use GYP to generate a Makefile: gyp --depth=. utf8rewind.gyp Build the project using `make`: make For a release build, specify the build type: make BUILDTYPE=Release Note that the generated Makefile does not contain a "clean" target. In order to do a full rebuild, you must delete the files in the "output" directory manually. ### Building on Mac OS X with XCode ### \note Building on Mac OS X is currently untested. Please let us know if you can help us in this regard. Open a command window at the project's root. Use GYP to generate a solution: tools\gyp\gyp --depth utf8rewind.gyp Open the solution in XCode and you can build the library and tests. ### Running the tests ### After generating a solution, build and run the "tests-rewind" project. Verify that all tests pass on your system configuration before continuing. ## Helping out ## As a user, you can help the project in a number of ways, in order of difficulty: * **Use it** - By using the library, you are helping the project spread. It is very important to us to have the project be used by as many different projects as possible. This will allow us to create better public interfaces. * **Spread the word** - If you find `utf8rewind` useful, recommend it to your friends or coworkers. * **Complain** - No library is perfect and `utf8rewind` is no exception. If you find a fault but lack the means (time, resources, etc.) to fix it, sending complaints to the proper channels can help the project out a lot. * **Write a failing test** - If a feature is not working as intended, you can prove it by writing a failing test. By sending the test to us, we can make the adjustments necessary for it to pass. * **Write a patch** - Patches include a code change that help tests to pass. A patch must always include a set of tests that fail to pass without the patch. All patches will be reviewed and possibly cleaned up before being accepted. ## Contact ## For inquiries, complaints and patches, please contact `{quinten}{lansu} {at} {gmail}.{com}`. Remove the brackets to get a valid e-mail address. ================================================ FILE: external/utf8rewind/include/utf8rewind/utf8rewind.h ================================================ /* Copyright (C) 2014-2016 Quinten Lansu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _UTF8REWIND_H_ #define _UTF8REWIND_H_ /*! \file \brief Public interface for UTF-8 functions. `utf8rewind` is a system library written in C designed to extend the default string handling functions with support for UTF-8 encoded text. */ /*! \defgroup public Public interface The public interface for the library. \defgroup version Version information Macros used to identify the version of the library. \defgroup global-config Global configuration Defines used for determining the global configuration of the system and your application. \defgroup errors Error codes Values returned by functions on error. \defgroup locales Locales Values used by functions that change behavior based on the input locale. \defgroup normalization Normalization flags Flags used as input for #utf8normalize and the result of #utf8isnormalized. \defgroup category Category flags Flags to be used with #utf8iscategory, to check whether code points in a string are part of that category. \defgroup types Types Custom type definitions used throughout the library. */ #include #include #include #include #include #include #include #include /*! \addtogroup version \{ */ /*! \def UTF8_VERSION_MAKE \brief Macro for creating a version number from a major, minor and bugfix number. */ #define UTF8_VERSION_MAKE(_major, _minor, _bugfix) \ ((_major) * 10000) + ((_minor) * 100) + (_bugfix) /*! \def UTF8_VERSION_MAJOR \brief The major version number of this release. */ #define UTF8_VERSION_MAJOR 1 /*! \def UTF8_VERSION_MINOR \brief The minor version number of this release. */ #define UTF8_VERSION_MINOR 5 /*! \def UTF8_VERSION_BUGFIX \brief The bugfix version number of this release. */ #define UTF8_VERSION_BUGFIX 0 /*! \def UTF8_VERSION \brief The version number as an integer. */ #define UTF8_VERSION \ UTF8_VERSION_MAKE(UTF8_VERSION_MAJOR, UTF8_VERSION_MINOR, UTF8_VERSION_BUGFIX) /*! \def UTF8_VERSION_STRING \brief The verion number as a string. */ #define UTF8_VERSION_STRING "1.5.0" /*! \def UTF8_VERSION_GUARD \brief Check if feature is supported by the current release. */ #define UTF8_VERSION_GUARD(_major, _minor, _bugfix) \ (UTF8_VERSION >= UTF8_VERSION_MAKE(_major, _minor, _bugfix)) /*! \} */ /*! \addtogroup errors \{ */ /*! \def UTF8_ERR_NONE \brief No errors. */ #define UTF8_ERR_NONE (0) /*! \def UTF8_ERR_INVALID_DATA \brief Input data is invalid. */ #define UTF8_ERR_INVALID_DATA (-1) /*! \def UTF8_ERR_INVALID_FLAG \brief Input flag is invalid. */ #define UTF8_ERR_INVALID_FLAG (-2) /*! \def UTF8_ERR_NOT_ENOUGH_SPACE \brief Not enough space in buffer to store result. */ #define UTF8_ERR_NOT_ENOUGH_SPACE (-3) /*! \def UTF8_ERR_OVERLAPPING_PARAMETERS \brief Input and output buffers overlap in memory. */ #define UTF8_ERR_OVERLAPPING_PARAMETERS (-4) /*! \def UTF8_ERR_INVALID_LOCALE \brief Invalid locale specified. */ #define UTF8_ERR_INVALID_LOCALE (-5) /*! \} */ /*! \addtogroup locales \{ */ /*! \def UTF8_LOCALE_DEFAULT \brief Used for text unaffected by changes in locale. */ #define UTF8_LOCALE_DEFAULT 0 /*! \def UTF8_LOCALE_LITHUANIAN \brief Changes behavior of the case mapping implementation when processing specific code points. For more information, see here: ftp://ftp.unicode.org/Public/UNIDATA/SpecialCasing.txt */ #define UTF8_LOCALE_LITHUANIAN 1 /*! \def UTF8_LOCALE_TURKISH_AND_AZERI_LATIN \brief Changes behavior of the case mapping implementation when processing specific code points. For more information, see here: ftp://ftp.unicode.org/Public/UNIDATA/SpecialCasing.txt */ #define UTF8_LOCALE_TURKISH_AND_AZERI_LATIN 2 /*! \def UTF8_LOCALE_MAXIMUM \brief Terminal value for locales. Valid locales do not exceed this value. */ #define UTF8_LOCALE_MAXIMUM 3 /*! \} */ /*! \addtogroup normalization \{ */ /*! \def UTF8_NORMALIZE_COMPOSE \brief Normalize input to Normalization Form C (NFC). */ #define UTF8_NORMALIZE_COMPOSE 0x00000001 /*! \def UTF8_NORMALIZE_DECOMPOSE \brief Normalize input to Normalization Form D (NFD). */ #define UTF8_NORMALIZE_DECOMPOSE 0x00000002 /*! \def UTF8_NORMALIZE_COMPATIBILITY \brief Changes Normalization Form from NFC to NFKC or from NFD to NFKD. */ #define UTF8_NORMALIZE_COMPATIBILITY 0x00000004 /*! \def UTF8_NORMALIZATION_RESULT_YES \brief Text is stable and does not need to be normalized. */ #define UTF8_NORMALIZATION_RESULT_YES (0) /*! \def UTF8_NORMALIZATION_RESULT_MAYBE \brief Text is unstable, but normalization may be skipped. */ #define UTF8_NORMALIZATION_RESULT_MAYBE (1) /*! \def UTF8_NORMALIZATION_RESULT_NO \brief Text is unstable and must be normalized. */ #define UTF8_NORMALIZATION_RESULT_NO (2) /*! \} */ /*! \addtogroup category \{ */ /*! \def UTF8_CATEGORY_LETTER_UPPERCASE \brief Uppercase letter code points, Lu in the Unicode database. */ #define UTF8_CATEGORY_LETTER_UPPERCASE 0x00000001 /*! \def UTF8_CATEGORY_LETTER_LOWERCASE \brief Lowercase letter code points, Ll in the Unicode database. */ #define UTF8_CATEGORY_LETTER_LOWERCASE 0x00000002 /*! \def UTF8_CATEGORY_LETTER_TITLECASE \brief Titlecase letter code points, Lt in the Unicode database. */ #define UTF8_CATEGORY_LETTER_TITLECASE 0x00000004 /*! \def UTF8_CATEGORY_LETTER_MODIFIER \brief Modifier letter code points, Lm in the Unicode database. */ #define UTF8_CATEGORY_LETTER_MODIFIER 0x00000008 /*! \def UTF8_CATEGORY_LETTER_OTHER \brief Other letter code points, Lo in the Unicode database. */ #define UTF8_CATEGORY_LETTER_OTHER 0x00000010 /*! \def UTF8_CATEGORY_LETTER \brief Combined flag for all letter categories. */ #define UTF8_CATEGORY_LETTER \ (UTF8_CATEGORY_LETTER_UPPERCASE | UTF8_CATEGORY_LETTER_LOWERCASE | \ UTF8_CATEGORY_LETTER_TITLECASE | UTF8_CATEGORY_LETTER_MODIFIER | \ UTF8_CATEGORY_LETTER_OTHER) /*! \def UTF8_CATEGORY_CASE_MAPPED \brief Combined flag for all letter categories with case mapping. */ #define UTF8_CATEGORY_CASE_MAPPED \ (UTF8_CATEGORY_LETTER_UPPERCASE | UTF8_CATEGORY_LETTER_LOWERCASE | \ UTF8_CATEGORY_LETTER_TITLECASE) /*! \def UTF8_CATEGORY_MARK_NON_SPACING \brief Non-spacing mark code points, Mn in the Unicode database. */ #define UTF8_CATEGORY_MARK_NON_SPACING 0x00000020 /*! \def UTF8_CATEGORY_MARK_SPACING \brief Spacing mark code points, Mc in the Unicode database. */ #define UTF8_CATEGORY_MARK_SPACING 0x00000040 /*! \def UTF8_CATEGORY_MARK_ENCLOSING \brief Enclosing mark code points, Me in the Unicode database. */ #define UTF8_CATEGORY_MARK_ENCLOSING 0x00000080 /*! \def UTF8_CATEGORY_MARK \brief Combined flag for all mark categories. */ #define UTF8_CATEGORY_MARK \ (UTF8_CATEGORY_MARK_NON_SPACING | UTF8_CATEGORY_MARK_SPACING | \ UTF8_CATEGORY_MARK_ENCLOSING) /*! \def UTF8_CATEGORY_NUMBER_DECIMAL \brief Decimal number code points, Nd in the Unicode database. */ #define UTF8_CATEGORY_NUMBER_DECIMAL 0x00000100 /*! \def UTF8_CATEGORY_NUMBER_LETTER \brief Letter number code points, Nl in the Unicode database. */ #define UTF8_CATEGORY_NUMBER_LETTER 0x00000200 /*! \def UTF8_CATEGORY_NUMBER_OTHER \brief Other number code points, No in the Unicode database. */ #define UTF8_CATEGORY_NUMBER_OTHER 0x00000400 /*! \def UTF8_CATEGORY_NUMBER \brief Combined flag for all number categories. */ #define UTF8_CATEGORY_NUMBER \ (UTF8_CATEGORY_NUMBER_DECIMAL | UTF8_CATEGORY_NUMBER_LETTER | \ UTF8_CATEGORY_NUMBER_OTHER) /*! \def UTF8_CATEGORY_PUNCTUATION_CONNECTOR \brief Connector punctuation category, Pc in the Unicode database. */ #define UTF8_CATEGORY_PUNCTUATION_CONNECTOR 0x00000800 /*! \def UTF8_CATEGORY_PUNCTUATION_DASH \brief Dash punctuation category, Pd in the Unicode database. */ #define UTF8_CATEGORY_PUNCTUATION_DASH 0x00001000 /*! \def UTF8_CATEGORY_PUNCTUATION_OPEN \brief Open punctuation category, Ps in the Unicode database. */ #define UTF8_CATEGORY_PUNCTUATION_OPEN 0x00002000 /*! \def UTF8_CATEGORY_PUNCTUATION_CLOSE \brief Close punctuation category, Pe in the Unicode database. */ #define UTF8_CATEGORY_PUNCTUATION_CLOSE 0x00004000 /*! \def UTF8_CATEGORY_PUNCTUATION_INITIAL \brief Initial punctuation category, Pi in the Unicode database. */ #define UTF8_CATEGORY_PUNCTUATION_INITIAL 0x00008000 /*! \def UTF8_CATEGORY_PUNCTUATION_FINAL \brief Final punctuation category, Pf in the Unicode database. */ #define UTF8_CATEGORY_PUNCTUATION_FINAL 0x00010000 /*! \def UTF8_CATEGORY_PUNCTUATION_OTHER \brief Other punctuation category, Po in the Unicode database. */ #define UTF8_CATEGORY_PUNCTUATION_OTHER 0x00020000 /*! \def UTF8_CATEGORY_PUNCTUATION \brief Combined flag for all punctuation categories. */ #define UTF8_CATEGORY_PUNCTUATION \ (UTF8_CATEGORY_PUNCTUATION_CONNECTOR | UTF8_CATEGORY_PUNCTUATION_DASH | \ UTF8_CATEGORY_PUNCTUATION_OPEN | UTF8_CATEGORY_PUNCTUATION_CLOSE | \ UTF8_CATEGORY_PUNCTUATION_INITIAL | UTF8_CATEGORY_PUNCTUATION_FINAL | \ UTF8_CATEGORY_PUNCTUATION_OTHER) /*! \def UTF8_CATEGORY_SYMBOL_MATH \brief Math symbol category, Sm in the Unicode database. */ #define UTF8_CATEGORY_SYMBOL_MATH 0x00040000 /*! \def UTF8_CATEGORY_SYMBOL_CURRENCY \brief Currency symbol category, Sc in the Unicode database. */ #define UTF8_CATEGORY_SYMBOL_CURRENCY 0x00080000 /*! \def UTF8_CATEGORY_SYMBOL_MODIFIER \brief Modifier symbol category, Sk in the Unicode database. */ #define UTF8_CATEGORY_SYMBOL_MODIFIER 0x00100000 /*! \def UTF8_CATEGORY_SYMBOL_OTHER \brief Other symbol category, So in the Unicode database. */ #define UTF8_CATEGORY_SYMBOL_OTHER 0x00200000 /*! \def UTF8_CATEGORY_SYMBOL \brief Combined flag for all symbol categories. */ #define UTF8_CATEGORY_SYMBOL \ (UTF8_CATEGORY_SYMBOL_MATH | UTF8_CATEGORY_SYMBOL_CURRENCY | \ UTF8_CATEGORY_SYMBOL_MODIFIER | UTF8_CATEGORY_SYMBOL_OTHER) /*! \def UTF8_CATEGORY_SEPARATOR_SPACE \brief Space separator category, Zs in the Unicode database. */ #define UTF8_CATEGORY_SEPARATOR_SPACE 0x00400000 /*! \def UTF8_CATEGORY_SEPARATOR_LINE \brief Line separator category, Zl in the Unicode database. */ #define UTF8_CATEGORY_SEPARATOR_LINE 0x00800000 /*! \def UTF8_CATEGORY_SEPARATOR_PARAGRAPH \brief Paragraph separator category, Zp in the Unicode database. */ #define UTF8_CATEGORY_SEPARATOR_PARAGRAPH 0x01000000 /*! \def UTF8_CATEGORY_SEPARATOR \brief Combined flag for all separator categories. */ #define UTF8_CATEGORY_SEPARATOR \ (UTF8_CATEGORY_SEPARATOR_SPACE | UTF8_CATEGORY_SEPARATOR_LINE | \ UTF8_CATEGORY_SEPARATOR_PARAGRAPH) /*! \def UTF8_CATEGORY_CONTROL \brief Control category, Cc in the Unicode database. */ #define UTF8_CATEGORY_CONTROL 0x02000000 /*! \def UTF8_CATEGORY_FORMAT \brief Format category, Cf in the Unicode database. */ #define UTF8_CATEGORY_FORMAT 0x04000000 /*! \def UTF8_CATEGORY_SURROGATE \brief Surrogate category, Cs in the Unicode database. */ #define UTF8_CATEGORY_SURROGATE 0x08000000 /*! \def UTF8_CATEGORY_PRIVATE_USE \brief Private use category, Co in the Unicode database. */ #define UTF8_CATEGORY_PRIVATE_USE 0x10000000 /*! \def UTF8_CATEGORY_UNASSIGNED \brief Unassigned category, Cn in the Unicode database. */ #define UTF8_CATEGORY_UNASSIGNED 0x20000000 /*! \def UTF8_CATEGORY_COMPATIBILITY \brief Flag used for maintaining backwards compatibility with POSIX functions, not found in the Unicode database. */ #define UTF8_CATEGORY_COMPATIBILITY 0x40000000 /*! \def UTF8_CATEGORY_IGNORE_GRAPHEME_CLUSTER \brief Flag used for checking only the general category of code points at the start of a grapheme cluster. */ #define UTF8_CATEGORY_IGNORE_GRAPHEME_CLUSTER 0x80000000 /*! \def UTF8_CATEGORY_ISCNTRL \brief Flag used for maintaining backwards compatibility with POSIX `iscntrl` function. */ #define UTF8_CATEGORY_ISCNTRL \ (UTF8_CATEGORY_COMPATIBILITY | \ UTF8_CATEGORY_CONTROL) /*! \def UTF8_CATEGORY_ISPRINT \brief Flag used for maintaining backwards compatibility with POSIX `isprint` function. */ #define UTF8_CATEGORY_ISPRINT \ (UTF8_CATEGORY_COMPATIBILITY | \ UTF8_CATEGORY_LETTER | UTF8_CATEGORY_NUMBER | \ UTF8_CATEGORY_PUNCTUATION | UTF8_CATEGORY_SYMBOL | \ UTF8_CATEGORY_SEPARATOR) /*! \def UTF8_CATEGORY_ISSPACE \brief Flag used for maintaining backwards compatibility with POSIX `isspace` function. */ #define UTF8_CATEGORY_ISSPACE \ (UTF8_CATEGORY_COMPATIBILITY | \ UTF8_CATEGORY_SEPARATOR_SPACE) /*! \def UTF8_CATEGORY_ISBLANK \brief Flag used for maintaining backwards compatibility with POSIX `isblank` function. */ #define UTF8_CATEGORY_ISBLANK \ (UTF8_CATEGORY_COMPATIBILITY | \ UTF8_CATEGORY_SEPARATOR_SPACE | UTF8_CATEGORY_PRIVATE_USE) /*! \def UTF8_CATEGORY_ISGRAPH \brief Flag used for maintaining backwards compatibility with POSIX `isgraph` function. */ #define UTF8_CATEGORY_ISGRAPH \ (UTF8_CATEGORY_COMPATIBILITY | \ UTF8_CATEGORY_LETTER | UTF8_CATEGORY_NUMBER | \ UTF8_CATEGORY_PUNCTUATION | UTF8_CATEGORY_SYMBOL) /*! \def UTF8_CATEGORY_ISPUNCT \brief Flag used for maintaining backwards compatibility with POSIX `ispunct` function. */ #define UTF8_CATEGORY_ISPUNCT \ (UTF8_CATEGORY_COMPATIBILITY | \ UTF8_CATEGORY_PUNCTUATION | UTF8_CATEGORY_SYMBOL) /*! \def UTF8_CATEGORY_ISALNUM \brief Flag used for maintaining backwards compatibility with POSIX `isalnum` function. */ #define UTF8_CATEGORY_ISALNUM \ (UTF8_CATEGORY_COMPATIBILITY | \ UTF8_CATEGORY_LETTER | UTF8_CATEGORY_NUMBER) /*! \def UTF8_CATEGORY_ISALPHA \brief Flag used for maintaining backwards compatibility with POSIX `isalpha` function. */ #define UTF8_CATEGORY_ISALPHA \ (UTF8_CATEGORY_COMPATIBILITY | \ UTF8_CATEGORY_LETTER) /*! \def UTF8_CATEGORY_ISUPPER \brief Flag used for maintaining backwards compatibility with POSIX `isupper` function. */ #define UTF8_CATEGORY_ISUPPER \ (UTF8_CATEGORY_COMPATIBILITY | \ UTF8_CATEGORY_LETTER_UPPERCASE) /*! \def UTF8_CATEGORY_ISLOWER \brief Flag used for maintaining backwards compatibility with POSIX `islower` function. */ #define UTF8_CATEGORY_ISLOWER \ (UTF8_CATEGORY_COMPATIBILITY | \ UTF8_CATEGORY_LETTER_LOWERCASE) /*! \def UTF8_CATEGORY_ISDIGIT \brief Flag used for maintaining backwards compatibility with POSIX `isdigit` function. */ #define UTF8_CATEGORY_ISDIGIT \ (UTF8_CATEGORY_COMPATIBILITY | \ UTF8_CATEGORY_NUMBER) /*! \def UTF8_CATEGORY_ISXDIGIT \brief Flag used for maintaining backwards compatibility with POSIX `isxdigit` function. */ #define UTF8_CATEGORY_ISXDIGIT \ (UTF8_CATEGORY_COMPATIBILITY | \ UTF8_CATEGORY_NUMBER | UTF8_CATEGORY_PRIVATE_USE) /*! \} */ /*! \addtogroup global-config \{ */ /*! \def UTF8_WCHAR_SIZE \brief Specifies the size of the `wchar_t` type. On Windows this is two bytes, on POSIX systems it is four. If not specified on the command line, the compiler tries to automatically determine the size of the `wchar_t` type based on the environment. */ #ifndef UTF8_WCHAR_SIZE #if (__SIZEOF_WCHAR_T__ == 4) || (WCHAR_MAX > UINT16_MAX) || (__WCHAR_MAX__ > UINT16_MAX) #define UTF8_WCHAR_SIZE (4) #else #define UTF8_WCHAR_SIZE (2) #endif #endif #if (UTF8_WCHAR_SIZE == 4) /*! \def UTF8_WCHAR_UTF32 \brief The `wchar_t` type is treated as UTF-32 (four byte fixed encoding). */ #define UTF8_WCHAR_UTF32 (1) #elif (UTF8_WCHAR_SIZE == 2) /*! \def UTF8_WCHAR_UTF16 \brief The `wchar_t` type is treated as UTF-16 (two byte variable length encoding). */ #define UTF8_WCHAR_UTF16 (1) #else #error Invalid size for wchar_t type. #endif /*! \def UTF8_API \brief Calling convention for public functions. */ #ifndef UTF8_API #ifdef __cplusplus #define UTF8_API extern "C" #else #define UTF8_API #endif #endif /*! \} */ /*! \addtogroup types \{ */ /*! \var utf16_t \brief UTF-16 encoded code point. */ typedef uint16_t utf16_t; /*! \var unicode_t \brief UTF-32 encoded code point. */ typedef uint32_t unicode_t; /*! \} */ /*! \addtogroup public \{ */ /*! \brief Get the length in code points of a UTF-8 encoded string. Example: \code{.c} uint8_t CheckPassword(const char* password) { size_t length = utf8len(password); return (length == utf8len("hunter2")); } \endcode \param[in] text UTF-8 encoded string. \return Length in code points. */ UTF8_API size_t utf8len(const char* text); /*! \brief Convert a UTF-16 encoded string to a UTF-8 encoded string. \note This function should only be called directly if you are positive that you are working with UTF-16 encoded text. If you're working with wide strings, take a look at #widetoutf8 instead. Example: \code{.c} uint8_t Player_SetNameUtf16(const utf16_t* name, size_t nameSize) { char buffer[256]; size_t buffer_size = 255; size_t converted_size; int32_t errors; if ((converted_size = utf16toutf8(name, nameSize, buffer, buffer_size, &errors)) == 0 || errors != UTF8_ERR_NONE) { return 0; } buffer[converted_size] = 0; return Player_SetName(converted_name); } \endcode \param[in] input UTF-16 encoded string. \param[in] inputSize Size of the input in bytes. \param[out] target Output buffer for the result, can be NULL. \param[in] targetSize Size of the output buffer in bytes. \param[out] errors Output for errors. \return Amount of bytes needed for storing output. \retval #UTF8_ERR_NONE No errors. \retval #UTF8_ERR_INVALID_DATA Failed to decode data. \retval #UTF8_ERR_OVERLAPPING_PARAMETERS Input and output buffers overlap in memory. \retval #UTF8_ERR_NOT_ENOUGH_SPACE Target buffer size is insufficient for result. \sa utf32toutf8 \sa widetoutf8 */ UTF8_API size_t utf16toutf8(const utf16_t* input, size_t inputSize, char* target, size_t targetSize, int32_t* errors); /*! \brief Convert a UTF-32 encoded string to a UTF-8 encoded string. \note This function should only be called directly if you are positive that you are working with UTF-32 encoded text. If you're working with wide strings, take a look at #widetoutf8 instead. Example: \code{.c} uint8_t Database_ExecuteQuery_Unicode(const unicode_t* query, size_t querySize) { char* converted = NULL; size_t converted_size; uint8_t result = 0; int32_t errors; if ((converted_size = utf32toutf8(query, querySize, NULL, 0, &errors)) == 0 || errors != UTF8_ERR_NONE) { goto cleanup; } converted = (char*)malloc(converted_size + 1); utf32toutf8(query, querySize, converted, converted_size, NULL); converted[converted_size] = 0; result = Database_ExecuteQuery(converted); cleanup: if (converted != NULL) { free(converted); converted = 0; } return result; } \endcode \param[in] input UTF-32 encoded string. \param[in] inputSize Size of the input in bytes. \param[out] target Output buffer for the result, can be NULL. \param[in] targetSize Size of the output buffer in bytes. \param[out] errors Output for errors. \return Amount of bytes needed for storing output. \retval #UTF8_ERR_NONE No errors. \retval #UTF8_ERR_INVALID_DATA Failed to decode data. \retval #UTF8_ERR_OVERLAPPING_PARAMETERS Input and output buffers overlap in memory. \retval #UTF8_ERR_NOT_ENOUGH_SPACE Target buffer size is insufficient for result. \sa utf16toutf8 \sa widetoutf8 */ UTF8_API size_t utf32toutf8(const unicode_t* input, size_t inputSize, char* target, size_t targetSize, int32_t* errors); /*! \brief Convert a wide string to a UTF-8 encoded string. Depending on the platform, wide strings are either UTF-16 or UTF-32 encoded. This function takes a wide string as input and automatically calls the correct conversion function. This allows for a cross-platform treatment of wide text and is preferable to using the UTF-16 or UTF-32 versions directly. Example: \code{.c} texture_t Texture_Load_Wide(const wchar_t* input) { char* converted = NULL; size_t converted_size; size_t input_size = wcslen(input) * sizeof(wchar_t); texture_t result = NULL; int32_t errors; if ((converted_size = widetoutf8(input, input_size, NULL, 0, &errors)) == 0 || errors != UTF8_ERR_NONE) { goto cleanup; } converted = (char*)malloc(converted_size + 1); widetoutf8(input, input_size, converted, converted_size, NULL); converted[converted_size / sizeof(wchar_t)] = 0; result = Texture_Load(converted); cleanup: if (converted != NULL) { free(converted); converted = NULL; } return result; } \endcode \param[in] input Wide-encoded string. \param[in] inputSize Size of the input in bytes. \param[out] target Output buffer for the result, can be NULL. \param[in] targetSize Size of the output buffer in bytes. \param[out] errors Output for errors. \return Amount of bytes needed for storing output. \retval #UTF8_ERR_NONE No errors. \retval #UTF8_ERR_INVALID_DATA Failed to decode data. \retval #UTF8_ERR_OVERLAPPING_PARAMETERS Input and output buffers overlap in memory. \retval #UTF8_ERR_NOT_ENOUGH_SPACE Target buffer size is insufficient for result. \sa utf8towide \sa utf16toutf8 \sa utf32toutf8 */ UTF8_API size_t widetoutf8(const wchar_t* input, size_t inputSize, char* target, size_t targetSize, int32_t* errors); /*! \brief Convert a UTF-8 encoded string to a UTF-16 encoded string. \note This function should only be called directly if you are positive that you *must* convert to UTF-16, independent of platform. If you're working with wide strings, take a look at #utf8towide instead. Erroneous byte sequences such as missing or illegal bytes or overlong encoding of code points (e.g. using five bytes to encode a sequence that can be represented by two bytes) are converted to the replacement character U+FFFD. Code points outside the Basic Multilingual Plane (BMP) will be converted to surrogate pairs, which use four bytes instead of two. Example: \code{.c} void Font_DrawText(int x, int y, const char* text) { utf16_t buffer[256]; size_t buffer_size = 255 * sizeof(utf16_t); int32_t errors; size_t converted_size = utf8toutf16(text, strlen(text), buffer, buffer_size, &errors); if (converted_size > 0 && errors == UTF8_ERR_NONE) { Legacy_DrawText(g_FontCurrent, x, y, (unsigned short*)buffer, converted_size / sizeof(utf16_t)); } } \endcode \param[in] input UTF-8 encoded string. \param[in] inputSize Size of the input in bytes. \param[out] target Output buffer for the result, can be NULL. \param[in] targetSize Size of the output buffer in bytes. \param[out] errors Output for errors. \return Amount of bytes needed for storing output. \retval #UTF8_ERR_NONE No errors. \retval #UTF8_ERR_INVALID_DATA Failed to decode data. \retval #UTF8_ERR_OVERLAPPING_PARAMETERS Input and output buffers overlap in memory. \retval #UTF8_ERR_NOT_ENOUGH_SPACE Target buffer size is insufficient for result. \sa utf8towide \sa utf8toutf32 */ UTF8_API size_t utf8toutf16(const char* input, size_t inputSize, utf16_t* target, size_t targetSize, int32_t* errors); /*! \brief Convert a UTF-8 encoded string to a UTF-32 encoded string. \note This function should only be called directly if you are positive that you *must* convert to UTF-32, independent of platform. If you're working with wide strings, take a look at #utf8towide instead. Erroneous byte sequences such as missing or illegal bytes or overlong encoding of code points (e.g. using five bytes to encode a sequence that can be represented by two bytes) are converted to the replacement character U+FFFD. Example: \code{.c} void TextField_AddCharacter(const char* encoded) { unicode_t code_point = 0; int32_t errors; utf8toutf32(encoded, strlen(encoded), &code_point, sizeof(unicode_t), &errors); if (errors == UTF8_ERR_NONE) { TextField_AddCodePoint(code_point); } } \endcode \param[in] input UTF-8 encoded string. \param[in] inputSize Size of the input in bytes. \param[out] target Output buffer for the result, can be NULL. \param[in] targetSize Size of the output buffer in bytes. \param[out] errors Output for errors. \return Amount of bytes needed for storing output. \retval #UTF8_ERR_NONE No errors. \retval #UTF8_ERR_INVALID_DATA Failed to decode data. \retval #UTF8_ERR_OVERLAPPING_PARAMETERS Input and output buffers overlap in memory. \retval #UTF8_ERR_NOT_ENOUGH_SPACE Target buffer size is insufficient for result. \sa utf8towide \sa utf8toutf16 */ UTF8_API size_t utf8toutf32(const char* input, size_t inputSize, unicode_t* target, size_t targetSize, int32_t* errors); /*! \brief Convert a UTF-8 encoded string to a wide string. Depending on the platform, wide strings are either UTF-16 or UTF-32 encoded. This function takes a UTF-8 encoded string as input and automatically calls the correct conversion function. This allows for a cross-platform treatment of wide text and is preferable to using the UTF-16 or UTF-32 versions directly. Erroneous byte sequences such as missing or illegal bytes or overlong encoding of code points (e.g. using five bytes to encode a sequence that can be represented by two bytes) are converted to the replacement character U+FFFD. \note Code points outside the Basic Multilingual Plane (BMP) are converted to surrogate pairs when using UTF-16. This means that strings containing characters outside the BMP converted on a platform with UTF-32 wide strings are *not* compatible with platforms with UTF-16 wide strings. \par Hence, it is preferable to store all data as UTF-8 and only convert to wide strings when required by a third-party interface. Example: \code{.c} void Window_SetTitle(void* windowHandle, const char* text) { size_t input_size = strlen(text); wchar_t* converted = NULL; size_t converted_size; int32_t errors; converted_size = utf8towide(text, input_size, NULL, 0, &errors); if (converted_size == 0 || errors != UTF8_ERR_NONE) { goto cleanup; } converted = (wchar_t*)malloc(converted_size + sizeof(wchar_t)); utf8towide(text, input_size, converted, converted_size, NULL); converted[converted_size / sizeof(wchar_t)] = 0; SetWindowTextW((HWND)windowHandle, converted); cleanup: if (converted != NULL) { free(converted); converted = NULL; } } \endcode \param[in] input UTF-8 encoded string. \param[in] inputSize Size of the input in bytes. \param[out] target Output buffer for the result, can be NULL. \param[in] targetSize Size of the output buffer in bytes. \param[out] errors Output for errors. \return Amount of bytes needed for storing output. \retval #UTF8_ERR_NONE No errors. \retval #UTF8_ERR_INVALID_DATA Failed to decode data. \retval #UTF8_ERR_OVERLAPPING_PARAMETERS Input and output buffers overlap in memory. \retval #UTF8_ERR_NOT_ENOUGH_SPACE Target buffer size is insufficient for result. \sa widetoutf8 \sa utf8toutf16 \sa utf8toutf32 */ UTF8_API size_t utf8towide(const char* input, size_t inputSize, wchar_t* target, size_t targetSize, int32_t* errors); /*! \brief Seek into a UTF-8 encoded string. Working with UTF-8 encoded strings can be tricky due to the nature of the variable-length encoding. Because one character no longer equals one byte, it can be difficult to skip around in a UTF-8 encoded string without decoding the code points. This function provides an interface similar to `fseek` in order to enable skipping to another part of the string. \note `textStart` must come before `text` in memory when seeking from the current or end position. Example: \code{.c} const char* text = "Press \xE0\x80\x13 to continue."; const char fixed[1024]; const char* commandStart; const char* commandEnd; memset(fixed, 0, sizeof(fixed)); commandStart = strstr(text, "\xE0\x80\x13"); if (commandStart == 0) { return 0; } strncpy(fixed, text, commandStart - text); strcat(fixed, "ENTER"); commandEnd = utf8seek(commandStart, strlen(commandStart), text, 1, SEEK_CUR); if (commandEnd != commandStart) { strcat(fixed, commandEnd); } \endcode \param[in] text Input string. \param[in] textSize Size of the complete input string in bytes, starting from `textStart`. \param[in] textStart Start of input string. \param[in] offset Requested offset in code points. \param[in] direction Direction to seek in. \arg `SEEK_SET` Offset is from the start of the string. \arg `SEEK_CUR` Offset is from the current position of the string. \arg `SEEK_END` Offset is from the end of the string. \return Pointer to offset string or no change on error. \sa utf8iscategory */ UTF8_API const char* utf8seek(const char* text, size_t textSize, const char* textStart, off_t offset, int direction); /*! \brief Returns the environment's locale as an enum value. This function retrieves the (thread-local) environment locale as an enum value in the \ref locales "list of locales". This value can be used with functions in this library that change behavior on certain inputs, depending on the specified locale. Unfortunately, no cross-platform way of setting and retrieving the system locale is available without adding dependencies to the library. Please refer to your operating system's manual to determine how to setup the system locale on your target system. \warning This function should not be used as a replacement for platform- specific methods for retrieving the locale. Its intended usage is to "guess" the desired locale by looking at the system locale. Example: \code{.c} uint8_t Employee_PrintNames(const char** names, size_t nameCount) { size_t locale = utf8envlocale(); char buffer[256]; size_t buffer_size = 255; int32_t errors; size_t i; for (i = 0; i < nameCount; ++i) { size_t buffer_filled; memset(buffer, 0, buffer_size); if ((buffer_filled = utf8toupper(names[i], strlen(names[i]), buffer, buffer_size, locale, &errors)) == 0 || errors != UTF8_ERR_NONE) { return 0; } Log_Print(buffer, buffer_filled); } return 1; } \endcode \return A specific \ref locales "locale" or #UTF8_LOCALE_DEFAULT. \sa utf8toupper \sa utf8tolower \sa utf8totitle \sa utf8casefold */ UTF8_API size_t utf8envlocale(); /*! \brief Convert UTF-8 encoded text to uppercase. This function allows conversion of UTF-8 encoded strings to uppercase without first changing the encoding to UTF-32. Conversion is fully compliant with the Unicode 7.0 standard. Although most code points can be converted in-place, there are notable exceptions. For example, U+00DF (LATIN SMALL LETTER SHARP S) maps to "U+0053 U+0053" (LATIN CAPITAL LETTER S and LATIN CAPITAL LETTER S) when converted to uppercase. Therefor, it is advised to first determine the size in bytes of the output by calling the function with a NULL output buffer. Only a handful of scripts make a distinction between upper and lowercase. In addition to modern scripts, such as Latin, Greek, Armenian and Cyrillic, a few historic or archaic scripts have case. The vast majority of scripts do not have case distinctions. \note Case mapping is not reversible. That is, `toUpper(toLower(x)) != toLower(toUpper(x))`. \warning Certain code points (or combinations of code points) apply rules based on the locale. For more information about these exceptional code points, please refer to the Unicode standard: ftp://ftp.unicode.org/Public/UNIDATA/SpecialCasing.txt Example: \code{.c} void Button_Draw(int32_t x, int32_t y, const char* text) { size_t input_size = strlen(text); char* converted = NULL; size_t converted_size; int32_t text_box_width, text_box_height; int32_t errors; if ((utf8toupper(text, input_size, NULL, 0, UTF8_LOCALE_DEFAULT, &errors)) == 0 || errors != UTF8_ERR_NONE) { goto cleanup; } converted = (char*)malloc(converted_size + 1); if (converted == NULL || utf8toupper(text, input_size, converted, converted_size, UTF8_LOCALE_DEFAULT, &errors) == 0 || errors != UTF8_ERR_NONE) { goto cleanup; } converted[converted_size] = 0; Font_GetTextDimensions(converted, &text_box_width, &text_box_height); Draw_BoxFilled(x - 4, y - 4, text_box_width + 8, text_box_height + 8, 0x088A08); Draw_BoxOutline(x - 4, y - 4, text_box_width + 8, text_box_height + 8, 0xA9F5A9); Font_DrawText(x + 2, y + 1, converted, 0x000000); Font_DrawText(x, y, converted, 0xFFFFFF); cleanup: if (converted != NULL) { free(converted); converted = NULL; } } \endcode \param[in] input UTF-8 encoded string. \param[in] inputSize Size of the input in bytes. \param[out] target Output buffer for the result, can be NULL. \param[in] targetSize Size of the output buffer in bytes. \param[in] locale Enables locale-specific behavior in the implementation. \ref locales "List of valid locales." \param[out] errors Output for errors. \return Amount of bytes needed to contain output. \retval #UTF8_ERR_NONE No errors. \retval #UTF8_ERR_INVALID_DATA Failed to decode data. \retval #UTF8_ERR_INVALID_LOCALE Invalid locale specified. \retval #UTF8_ERR_OVERLAPPING_PARAMETERS Input and output buffers overlap in memory. \retval #UTF8_ERR_NOT_ENOUGH_SPACE Target buffer size is insufficient for result. \sa utf8tolower \sa utf8totitle \sa utf8casefold */ UTF8_API size_t utf8toupper(const char* input, size_t inputSize, char* target, size_t targetSize, size_t locale, int32_t* errors); /*! \brief Convert UTF-8 encoded text to lowercase. This function allows conversion of UTF-8 encoded strings to lowercase without first changing the encoding to UTF-32. Conversion is fully compliant with the Unicode 7.0 standard. Although most code points can be converted to lowercase in-place, there are notable exceptions. For example, U+0130 (LATIN CAPITAL LETTER I WITH DOT ABOVE) maps to "U+0069 U+0307" (LATIN SMALL LETTER I and COMBINING DOT ABOVE) when converted to lowercase. Therefor, it is advised to first determine the size in bytes of the output by calling the function with a NULL output buffer. Only a handful of scripts make a distinction between upper- and lowercase. In addition to modern scripts, such as Latin, Greek, Armenian and Cyrillic, a few historic or archaic scripts have case. The vast majority of scripts do not have case distinctions. \note Case mapping is not reversible. That is, `toUpper(toLower(x)) != toLower(toUpper(x))`. \warning Certain code points (or combinations of code points) apply rules based on the locale. For more information about these exceptional code points, please refer to the Unicode standard: ftp://ftp.unicode.org/Public/UNIDATA/SpecialCasing.txt Example: \code{.c} author_t* Author_ByName(const char* name) { author_t* result = NULL; size_t name_size = strlen(name); char* converted = NULL; size_t converted_size; int32_t errors; size_t i; if ((converted_size = utf8tolower(name, name_size, NULL, 0, UTF8_LOCALE_DEFAULT, &errors)) == 0 || errors != UTF8_ERR_NONE) { goto cleanup; } converted = (char*)malloc(converted_size + 1); if (converted == NULL || utf8tolower(name, name_size, converted, converted_size, UTF8_LOCALE_DEFAULT, &errors) == 0 || errors != UTF8_ERR_NONE) { goto cleanup; } converted[converted_size] = 0; for (i = 0; i < g_AuthorCount; ++i) { if (!strcmp(g_Author[i].name, converted)) { result = &g_Author[i]; break; } } cleanup: if (converted != NULL) { free(converted); converted = NULL; } return result; } \endcode \param[in] input UTF-8 encoded string. \param[in] inputSize Size of the input in bytes. \param[out] target Output buffer for the result, can be NULL. \param[in] targetSize Size of the output buffer in bytes. \param[in] locale Enables locale-specific behavior in the implementation. \ref locales "List of valid locales." \param[out] errors Output for errors. \return Amount of bytes needed for storing output. \retval #UTF8_ERR_NONE No errors. \retval #UTF8_ERR_INVALID_DATA Failed to decode data. \retval #UTF8_ERR_INVALID_LOCALE Invalid locale specified. \retval #UTF8_ERR_OVERLAPPING_PARAMETERS Input and output buffers overlap in memory. \retval #UTF8_ERR_NOT_ENOUGH_SPACE Target buffer size is insufficient for result. \sa utf8toupper \sa utf8totitle \sa utf8casefold */ UTF8_API size_t utf8tolower(const char* input, size_t inputSize, char* target, size_t targetSize, size_t locale, int32_t* errors); /*! \brief Convert UTF-8 encoded text to titlecase. This function allows conversion of UTF-8 encoded strings to titlecase without first changing the encoding to UTF-32. Conversion is fully compliant with the Unicode 7.0 standard. Titlecase requires a bit more explanation than uppercase and lowercase, because it is not a common text transformation. Titlecase uses uppercase for the first letter of each word and lowercase for the rest. Words are defined as "collections of code points with general category Lu, Ll, Lt, Lm or Lo according to the Unicode database". Effectively, any type of punctuation can break up a word, even if this is not grammatically valid. This happens because the titlecasing algorithm does not and cannot take grammar rules into account. Text | Titlecase -------------------------------------|------------------------------------- The running man | The Running Man NATO Alliance | Nato Alliance You're amazing at building libraries | You'Re Amazing At Building Libraries Although most code points can be converted to titlecase in-place, there are notable exceptions. For example, U+00DF (LATIN SMALL LETTER SHARP S) maps to "U+0053 U+0073" (LATIN CAPITAL LETTER S and LATIN SMALL LETTER S) when converted to titlecase. Therefor, it is advised to first determine the size in bytes of the output by calling the function with a NULL output buffer. Only a handful of scripts make a distinction between upper- and lowercase. In addition to modern scripts, such as Latin, Greek, Armenian and Cyrillic, a few historic or archaic scripts have case. The vast majority of scripts do not have case distinctions. \note Case mapping is not reversible. That is, `toUpper(toLower(x)) != toLower(toUpper(x))`. \warning Certain code points (or combinations of code points) apply rules based on the locale. For more information about these exceptional code points, please refer to the Unicode standard: ftp://ftp.unicode.org/Public/UNIDATA/SpecialCasing.txt Example: \code{.c} void Book_SetTitle(book_t* book, const char* title) { size_t converted_size; int32_t errors; size_t i; if ((converted_size = utf8totitle(title, strlen(title), book->title, sizeof(book->title) - 1, UTF8_LOCALE_DEFAULT, &errors)) == 0 || errors != UTF8_ERR_NONE) { memset(book->title, 0, sizeof(book->title)); return; } book->title[converted_size] = 0; } \endcode \param[in] input UTF-8 encoded string. \param[in] inputSize Size of the input in bytes. \param[out] target Output buffer for the result, can be NULL. \param[in] targetSize Size of the output buffer in bytes. \param[in] locale Enables locale-specific behavior in the implementation. \ref locales "List of valid locales." \param[out] errors Output for errors. \return Amount of bytes needed for storing output. \retval #UTF8_ERR_NONE No errors. \retval #UTF8_ERR_INVALID_DATA Failed to decode data. \retval #UTF8_ERR_INVALID_LOCALE Invalid locale specified. \retval #UTF8_ERR_OVERLAPPING_PARAMETERS Input and output buffers overlap in memory. \retval #UTF8_ERR_NOT_ENOUGH_SPACE Target buffer size is insufficient for result. \sa utf8tolower \sa utf8toupper \sa utf8casefold */ UTF8_API size_t utf8totitle(const char* input, size_t inputSize, char* target, size_t targetSize, size_t locale, int32_t* errors); /*! \brief Remove case distinction from UTF-8 encoded text. Case folding is the process of eliminating differences between code points concerning case mapping. It is most commonly used for comparing strings in a case-insensitive manner. Conversion is fully compliant with the Unicode 7.0 standard. Although similar to lowercasing text, there are significant differences. For one, case folding does _not_ take locale into account when converting. In some cases, case folding can be up to 20% faster than lowercasing the same text, but the result cannot be treated as correct lowercased text. Only two locale-specific exception are made when case folding text. In Turkish, U+0049 LATIN CAPITAL LETTER I maps to U+0131 LATIN SMALL LETTER DOTLESS I and U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE maps to U+0069 LATIN SMALL LETTER I. Although most code points can be case folded in-place, there are notable exceptions. For example, U+0130 (LATIN CAPITAL LETTER I WITH DOT ABOVE) maps to "U+0069 U+0307" (LATIN SMALL LETTER I and COMBINING DOT ABOVE) when converted to lowercase. Therefor, it is advised to first determine the size in bytes of the output by calling the function with a NULL output buffer. Only a handful of scripts make a distinction between upper- and lowercase. In addition to modern scripts, such as Latin, Greek, Armenian and Cyrillic, a few historic or archaic scripts have case. The vast majority of scripts do not have case distinctions. Example: \code{.c} int32_t Command_ParseCommand(const char* argument) { char* buffer = NULL; size_t buffer_size = 0; int32_t errors; int32_t result = 0; if ((buffer_size = utf8casefold(argument, strlen(argument), NULL, 0, UTF8_LOCALE_DEFAULT, &errors)) == 0 || errors != UTF8_ERR_NONE) { result = -1; goto cleanup; } buffer = (char*)malloc(buffer_size); if (buffer == NULL || utf8casefold(argument, strlen(argument), buffer, buffer_size, UTF8_LOCALE_DEFAULT, &errors) == 0 || errors != UTF8_ERR_NONE) { result = -1; goto cleanup; } if (!strncmp(buffer, "-username", strlen("-username"))) { result = eCommand_Username; } else if ( !strncmp(buffer, "-password", strlen("-password"))) { result = eCommand_Password; } else if ( !strncmp(buffer, "-message", strlen("-message"))) { result = eCommand_Message; } cleanup: if (buffer != NULL) { free(buffer); buffer = NULL; } return result; } \endcode \param[in] input UTF-8 encoded string. \param[in] inputSize Size of the input in bytes. \param[out] target Output buffer for the result, can be NULL. \param[in] targetSize Size of the output buffer in bytes. \param[in] locale Enables locale-specific behavior in the implementation. \ref locales "List of valid locales." \param[out] errors Output for errors. \return Amount of bytes needed for storing output. \retval #UTF8_ERR_NONE No errors. \retval #UTF8_ERR_INVALID_DATA Failed to decode data. \retval #UTF8_ERR_INVALID_LOCALE Invalid locale specified. \retval #UTF8_ERR_OVERLAPPING_PARAMETERS Input and output buffers overlap in memory. \retval #UTF8_ERR_NOT_ENOUGH_SPACE Target buffer size is insufficient for result. \sa utf8tolower \sa utf8toupper \sa utf8totitle */ UTF8_API size_t utf8casefold(const char* input, size_t inputSize, char* target, size_t targetSize, size_t locale, int32_t* errors); /*! \brief Check if a string is stable in the specified Unicode Normalization Form. This function can be used as a preprocessing step, before attempting to normalize a string. Normalization is a very expensive process, it is often cheaper to first determine if the string is unstable in the requested normalization form. The result of the check will be YES if the string is stable and MAYBE or NO if it is unstable. If the result is MAYBE, the string does not necessarily have to be normalized. If the result is unstable, the offset parameter is set to the offset for the first unstable code point. If the string is stable, the offset is equivalent to the length of the string in bytes. You must specify the desired Unicode Normalization Form by using a combination of flags: Unicode | Flags ---------------------------- | --------------------------------------------------------- Normalization Form C (NFC) | #UTF8_NORMALIZE_COMPOSE Normalization Form KC (NFKC) | #UTF8_NORMALIZE_COMPOSE + #UTF8_NORMALIZE_COMPATIBILITY Normalization Form D (NFD) | #UTF8_NORMALIZE_DECOMPOSE Normalization Form KD (NFKD) | #UTF8_NORMALIZE_DECOMPOSE + #UTF8_NORMALIZE_COMPATIBILITY For more information, please review [Unicode Standard Annex #15 - Unicode Normalization Forms](http://www.unicode.org/reports/tr15/). Example: \code{.c} uint8_t Text_InspectComposed(const char* text) { const char* src = text; size_t src_size = strlen(text); size_t offset; size_t total_offset; if (utf8isnormalized(src, src_size, UTF8_NORMALIZE_COMPOSE, &offset) == UTF8_NORMALIZATION_RESULT_YES) { printf("Clean!\n"); return 1; } total_offset = offset; do { const char* next; printf("Unstable at byte %d\n", total_offset); next = utf8seek(src, text, 1, SEEK_CUR); if (next == src) { break; } total_offset += offset; src = next; src_size -= next - src; } while (utf8isnormalized(src, src_size, UTF8_NORMALIZE_COMPOSE, &offset) != UTF8_NORMALIZATION_RESULT_YES); return 0; } \endcode \param[in] input UTF-8 encoded string. \param[in] inputSize Size of the input in bytes. \param[in] flags Desired normalization form. Must be a combination of \ref normalization "normalization flags". \param[out] offset Offset to first unstable code point or length of input in bytes if stable. \retval #UTF8_NORMALIZATION_RESULT_YES Input is stable and does not have to be normalized. \retval #UTF8_NORMALIZATION_RESULT_MAYBE Input is unstable, but normalization may be skipped. \retval #UTF8_NORMALIZATION_RESULT_NO Input is unstable and must be normalized. \sa utf8normalize */ UTF8_API uint8_t utf8isnormalized(const char* input, size_t inputSize, size_t flags, size_t* offset); /*! \brief Normalize a string to the specified Unicode Normalization Form. The Unicode standard defines two standards for equivalence between characters: canonical and compatibility equivalence. Canonically equivalent characters and sequence represent the same abstract character and must be rendered with the same appearance and behavior. Compatibility equivalent characters have a weaker equivalence and may be rendered differently. Unicode Normalization Forms are formally defined standards that can be used to test whether any two strings of characters are equivalent to each other. This equivalence may be canonical or compatibility. The algorithm puts all combining marks into a specified order and uses the rules for decomposition and composition to transform the string into one of four Unicode Normalization Forms. A binary comparison can then be used to determine equivalence. These are the Unicode Normalization Forms: Form | Description ---------------------------- | --------------------------------------------- Normalization Form D (NFD) | Canonical decomposition Normalization Form C (NFC) | Canonical decomposition, followed by canonical composition Normalization Form KD (NFKD) | Compatibility decomposition Normalization Form KC (NFKC) | Compatibility decomposition, followed by canonical composition `utf8normalize` can be used to transform text into one of these forms. You must specify the desired Unicode Normalization Form by using a combination of flags: Form | Flags ----------------------------- | --------------------------------------------------------- Normalization Form D (NFD) | #UTF8_NORMALIZE_DECOMPOSE Normalization Form C (NFC) | #UTF8_NORMALIZE_COMPOSE Normalization Form KD (NFKD) | #UTF8_NORMALIZE_DECOMPOSE + #UTF8_NORMALIZE_COMPATIBILITY Normalization Form KC (NFKC) | #UTF8_NORMALIZE_COMPOSE + #UTF8_NORMALIZE_COMPATIBILITY For more information, please review [Unicode Standard Annex #15 - Unicode Normalization Forms](http://www.unicode.org/reports/tr15/). \note Unnormalized text is rare in the wild. As an example, *all* text found on the Internet as HTML source code must be encoded as NFC, as specified by the W3C. Example: \code{.c} void Font_RenderTextNormalized(const char* input) { const char* src = NULL; const char* src_start; size_t src_size; char* converted = NULL; size_t converted_size = 0; size_t input_size = strlen(input); if (utf8isnormalized(input, input_size, UTF8_NORMALIZE_COMPOSE, NULL) != UTF8_NORMALIZATION_RESULT_YES) { int32_t errors; converted_size = utf8normalize(input, input_size, NULL, 0, UTF8_NORMALIZE_COMPOSE, &errors); if (converted_size > 0 && errors == UTF8_ERR_NONE) { converted = (char*)malloc(converted_size + 1); utf8normalize(input, input_size, converted, converted_size, UTF8_NORMALIZE_COMPOSE, NULL); converted[converted_size] = 0; src = (const char*)converted; src_size = converted_size; } } if (src == NULL) { src = (const char*)input; src_size = input_size; } src_start = src; while (src_size > 0) { const char* next; int32_t errors; next = utf8seek(src, src_size, src_start, 1, SEEK_CUR); if (next == src) { break; } unicode_t code_point; utf8toutf32(src, (size_t)(next - src), &code_point, sizeof(unicode_t), &errors); if (errors != UTF8_ERR_NONE) { break; } Font_RenderCodePoint(code_point); src_size -= next - src; src = next; } if (converted != NULL) { free(converted); converted = NULL; } } \endcode \param[in] input UTF-8 encoded string. \param[in] inputSize Size of the input in bytes. \param[out] target Output buffer for the result, can be NULL. \param[in] targetSize Size of the output buffer in bytes. \param[in] flags Desired normalization form. Must be a combination of #UTF8_NORMALIZE_COMPOSE, #UTF8_NORMALIZE_DECOMPOSE and #UTF8_NORMALIZE_COMPATIBILITY. \param[out] errors Output for errors. \return Amount of bytes needed for storing output. \retval #UTF8_ERR_NONE No errors. \retval #UTF8_ERR_INVALID_FLAG Invalid combination of flags was specified. \retval #UTF8_ERR_INVALID_DATA Failed to decode data. \retval #UTF8_ERR_OVERLAPPING_PARAMETERS Input and output buffers overlap in memory. \retval #UTF8_ERR_NOT_ENOUGH_SPACE Target buffer size is insufficient for result. \sa utf8isnormalized */ UTF8_API size_t utf8normalize(const char* input, size_t inputSize, char* target, size_t targetSize, size_t flags, int32_t* errors); /*! \brief Check if the input string conforms to the category specified by the flags. This function can be used to check if the code points in a string are part of a category. Valid flags are members of the \ref category "list of categories". The category for a code point is defined as part of the entry in UnicodeData.txt, the data file for the Unicode code point database. \note The function is _greedy_. This means it will try to match as many code points with the matching category flags as possible and return the offset in the input in bytes. If this is undesired behavior, use `utf8seek` to seek in the input first before matching it with the category flags. By default, the function will treat grapheme clusters as a single code point. This means that the following string: Code point | Canonical combining class | General category | Name ---------- | ------------------------- | --------------------- | ---------------------- U+0045 | 0 | Lu (Uppercase letter) | LATIN CAPITAL LETTER E U+0300 | 230 | Mn (Non-spacing mark) | COMBINING GRAVE ACCENT Will match with #UTF8_CATEGORY_LETTER_UPPERCASE in its entirety, because the COMBINING GRAVE ACCENT is treated as part of the grapheme cluster. This is useful when e.g. creating a text parser, because you do not have to normalize the text first. If this is undesired behavior, specify the #UTF8_CATEGORY_IGNORE_GRAPHEME_CLUSTER flag. \warning In order to maintain backwards compatibility with POSIX functions like `isdigit` and `isspace`, compatibility flags have been provided. Note, however, that the result is only guaranteed to be correct for code points in the Basic Latin range, between U+0000 and 0+007F. Combining a compatibility flag with a regular category flag will result in undefined behavior. Example: \code{.c} const char* Parser_NextIdentifier(char** output, size_t* outputSize, const char* input, size_t inputSize) { const char* src = input; size_t src_size = inputSize; size_t whitespace_size; size_t identifier_size; whitespace_size = utf8iscategory(src, src_size, UTF8_CATEGORY_SEPARATOR_SPACE); if (whitespace_size == 0) { whitespace_size = utf8iscategory(src, src_size, UTF8_CATEGORY_ISSPACE); } if (whitespace_size > 0) { if (whitespace_size >= src_size) { return src + src_size; } src += whitespace_size; src_size -= whitespace_size; } identifier_size = utf8iscategory(src, src_size, UTF8_CATEGORY_LETTER | UTF8_CATEGORY_PUNCTUATION_CONNECTOR | UTF8_CATEGORY_PUNCTUATION_DASH); if (identifier_size == 0) { return src; } *output = (char*)malloc(identifier_size + 1); memcpy(*output, src, identifier_size); (*output)[identifier_size] = 0; *outputSize = identifier_size; if (identifier_size >= src_size) { return src + src_size; } return src + identifier_size; } \endcode \param[in] input UTF-8 encoded string. \param[in] inputSize Size of the input in bytes. \param[in] flags Requested category. Must be a combination of \ref category "category flags" or a single compatibility flag. \return Number of bytes in the input that conform to the specified category flags. \sa utf8seek */ UTF8_API size_t utf8iscategory(const char* input, size_t inputSize, size_t flags); /*! \} */ #endif /* _UTF8REWIND_H_ */ ================================================ FILE: external/utf8rewind/makefile ================================================ # bleugh. # so we can call from our main makefile. CSRC := $(shell find source -name "*.c") COBJ := $(CSRC:.c=.c.o) .PHONY: all all: ../libutf8rewind.a @: ../libutf8rewind.a: $(COBJ) @echo "# libutf8rewind" @$(AR) rcs ../libutf8rewind.a $(COBJ) %.c.o: %.c @echo "# utf8rewind/$(notdir $<)" @$(CC) -std=c11 -O3 -c -Iinclude -o $@ $< ================================================ FILE: external/utf8rewind/source/internal/base.h ================================================ /* Copyright (C) 2014-2016 Quinten Lansu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _UTF8REWIND_INTERNAL_BASE_H_ #define _UTF8REWIND_INTERNAL_BASE_H_ /*! \file \brief Base header for internal interface. \cond INTERNAL */ #include "../../include/utf8rewind/utf8rewind.h" #if defined(__GNUC__) && !defined(COMPILER_ICC) #define UTF8_UNUSED(_parameter) _parameter __attribute__ ((unused)) #else #define UTF8_UNUSED(_parameter) _parameter #endif #define UTF8_SET_ERROR(_error) \ if (errors != 0) { *errors = UTF8_ERR_ ## _error; } /* Validates input before transforming */ /* Check for parameter overlap using the separating axis theorem */ #define UTF8_VALIDATE_PARAMETERS_CHAR(_inputType, _result) \ if (input == 0) { \ UTF8_SET_ERROR(INVALID_DATA); \ return _result; \ } \ else if (inputSize < sizeof(_inputType)) { \ if (target != 0) { \ if (targetSize < 3) { \ UTF8_SET_ERROR(NOT_ENOUGH_SPACE); \ return _result; \ } \ memcpy(target, REPLACEMENT_CHARACTER_STRING, REPLACEMENT_CHARACTER_STRING_LENGTH); \ } \ UTF8_SET_ERROR(INVALID_DATA); \ return _result + REPLACEMENT_CHARACTER_STRING_LENGTH; \ } \ if (target != 0 && targetSize == 0) { \ UTF8_SET_ERROR(NOT_ENOUGH_SPACE); \ return _result; \ } \ if ((char*)input == target) { \ UTF8_SET_ERROR(OVERLAPPING_PARAMETERS); \ return _result; \ } \ { \ char* input_center = (char*)input + (inputSize / 2); \ char* target_center = target + (targetSize / 2); \ size_t delta = (size_t)((input_center > target_center) ? (input_center - target_center) : (target_center - input_center)); \ if (delta < (inputSize + targetSize) / 2) { \ UTF8_SET_ERROR(OVERLAPPING_PARAMETERS); \ return _result; \ } \ } #define UTF8_VALIDATE_PARAMETERS(_inputType, _outputType, _result) \ if (input == 0) { \ UTF8_SET_ERROR(INVALID_DATA); \ return _result; \ } \ else if (inputSize < sizeof(_inputType)) { \ if (target != 0) { \ if (targetSize < sizeof(_outputType)) { \ UTF8_SET_ERROR(NOT_ENOUGH_SPACE); \ return _result; \ } \ *target = REPLACEMENT_CHARACTER; \ } \ UTF8_SET_ERROR(INVALID_DATA); \ return _result + sizeof(_outputType); \ } \ if (target != 0 && targetSize < sizeof(_outputType)) { \ UTF8_SET_ERROR(NOT_ENOUGH_SPACE); \ return _result; \ } \ if ((char*)input == (char*)target) { \ UTF8_SET_ERROR(OVERLAPPING_PARAMETERS); \ return _result; \ } \ { \ char* input_center = (char*)input + (inputSize / 2); \ char* target_center = (char*)target + (targetSize / 2); \ size_t delta = (size_t)((input_center > target_center) ? (input_center - target_center) : (target_center - input_center)); \ if (delta < (inputSize + targetSize) / 2) { \ UTF8_SET_ERROR(OVERLAPPING_PARAMETERS); \ return _result; \ } \ } /*! \endcond */ #endif /* _UTF8REWIND_INTERNAL_BASE_H_ */ ================================================ FILE: external/utf8rewind/source/internal/casemapping.c ================================================ /* Copyright (C) 2014-2016 Quinten Lansu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "casemapping.h" #include "base.h" #include "codepoint.h" #include "database.h" #include "streaming.h" static const char basic_latin_lowercase_table[58] = { /* LATIN CAPITAL LETTER A - LATIN CAPITAL LETTER Z */ 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x5B, /* LEFT SQUARE BRACKET */ 0x5C, /* REVERSE SOLIDUS */ 0x5D, /* RIGHT SQUARE BRACKET */ 0x5E, /* CIRCUMFLEX ACCENT */ 0x5F, /* LOW LINE */ 0x60, /* GRAVE ACCENT */ /* LATIN SMALL LETTER A - LATIN SMALL LETTER Z */ 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A }; static const char basic_latin_uppercase_table[58] = { /* LATIN CAPITAL LETTER A - LATIN CAPITAL LETTER Z */ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, /* LEFT SQUARE BRACKET */ 0x5C, /* REVERSE SOLIDUS */ 0x5D, /* RIGHT SQUARE BRACKET */ 0x5E, /* CIRCUMFLEX ACCENT */ 0x5F, /* LOW LINE */ 0x60, /* GRAVE ACCENT */ /* LATIN SMALL LETTER A - LATIN SMALL LETTER Z */ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A }; uint8_t casemapping_initialize( CaseMappingState* state, const char* input, size_t inputSize, char* target, size_t targetSize, const uint32_t* propertyIndex1, const uint32_t* propertyIndex2, const uint32_t* propertyData, uint8_t quickCheck, size_t locale, int32_t* errors) { memset(state, 0, sizeof(CaseMappingState)); if (locale >= UTF8_LOCALE_MAXIMUM) { UTF8_SET_ERROR(INVALID_LOCALE); return 0; } state->src = input; state->src_size = inputSize; state->dst = target; state->dst_size = targetSize; state->property_index1 = propertyIndex1; state->property_index2 = propertyIndex2; state->property_data = propertyData; state->quickcheck_flags = quickCheck; state->locale = locale; return 1; } size_t casemapping_execute(CaseMappingState* state, int32_t* errors) { uint8_t qc_casemapped = 0; uint8_t bytes_needed = 0; const char* resolved = 0; StreamState stream; uint8_t i; /* Read next code point */ state->last_code_point_size = codepoint_read(state->src, state->src_size, &state->last_code_point); if (state->last_code_point_size == 0) { goto invaliddata; } /* Check for invalid characters */ if (state->last_code_point == REPLACEMENT_CHARACTER) { /* Get code point properties */ state->last_canonical_combining_class = CCC_NOT_REORDERED; state->last_general_category = UTF8_CATEGORY_SYMBOL_OTHER; resolved = REPLACEMENT_CHARACTER_STRING; bytes_needed = REPLACEMENT_CHARACTER_STRING_LENGTH; goto writeresolved; } if (state->locale == UTF8_LOCALE_TURKISH_AND_AZERI_LATIN) { /* Code point General Category does not need to be modified, because all mappings result in the same General Category */ if (state->property_data == LowercaseDataPtr) { if (state->last_code_point == CP_LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE) { state->last_code_point = CP_LATIN_SMALL_LETTER_I; resolved = "i"; bytes_needed = 1; } else if ( state->last_code_point == CP_LATIN_CAPITAL_LETTER_I) { if (state->src_size == 0) { /* Early-out for easy case */ state->last_code_point = CP_LATIN_SMALL_LETTER_DOTLESS_I; resolved = "\xC4\xB1"; bytes_needed = 2; } else { uint8_t found = 0; /* Initialize stream and read the next sequence */ if (!stream_initialize(&stream, state->src, state->src_size) || !stream_read(&stream, QuickCheckNFCIndexPtr, QuickCheckNFCDataPtr)) { goto writeregular; } /* Erase COMBINING DOT ABOVE from sequence */ for (i = stream.current - 1; i > 0; --i) { if (stream.codepoint[i] == CP_COMBINING_DOT_ABOVE) { stream.canonical_combining_class[i] = CCC_INVALID; found++; } } /* Stabilize sequence and write to output */ if (!stream.stable || found > 0) { stream_reorder(&stream); stream.current -= found; } stream.codepoint[0] = (found > 0) ? CP_LATIN_SMALL_LETTER_I : CP_LATIN_SMALL_LETTER_DOTLESS_I; goto writestream; } } } else { if (state->last_code_point == CP_LATIN_SMALL_LETTER_I) { state->last_code_point = CP_LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE; resolved = "\xC4\xB0"; bytes_needed = 2; } else if ( state->last_code_point == CP_LATIN_SMALL_LETTER_DOTLESS_I) { state->last_code_point = CP_LATIN_CAPITAL_LETTER_I; resolved = "I"; bytes_needed = 1; } } /* Check if mapping succeeded */ if (resolved != 0) { /* Code point properties */ state->last_general_category = UTF8_CATEGORY_LETTER; goto writeresolved; } } else if ( state->locale == UTF8_LOCALE_LITHUANIAN) { if (state->property_data == LowercaseDataPtr) { unicode_t cp_additional_accent = 0; uint8_t write_soft_dot = 1; switch (state->last_code_point) { case CP_LATIN_CAPITAL_LETTER_I: state->last_code_point = CP_LATIN_SMALL_LETTER_I; break; case CP_LATIN_CAPITAL_LETTER_J: state->last_code_point = CP_LATIN_SMALL_LETTER_J; break; case CP_LATIN_CAPITAL_LETTER_I_WITH_OGONEK: state->last_code_point = CP_LATIN_SMALL_LETTER_I_WITH_OGONEK; break; case CP_LATIN_CAPITAL_LETTER_I_WITH_GRAVE: state->last_code_point = CP_LATIN_SMALL_LETTER_I; cp_additional_accent = CP_COMBINING_GRAVE_ACCENT; break; case CP_LATIN_CAPITAL_LETTER_I_WITH_ACUTE: state->last_code_point = CP_LATIN_SMALL_LETTER_I; cp_additional_accent = CP_COMBINING_ACUTE_ACCENT; break; case CP_LATIN_CAPITAL_LETTER_I_WITH_TILDE: state->last_code_point = CP_LATIN_SMALL_LETTER_I; cp_additional_accent = CP_COMBINING_TILDE_ACCENT; break; default: goto writeregular; } /* Initialize stream and read the next sequence */ if (!stream_initialize(&stream, state->src, state->src_size) || !stream_read(&stream, QuickCheckNFCIndexPtr, QuickCheckNFCDataPtr)) { goto writeregular; } /* Assign the lowercase code point to the start of the stream */ stream.codepoint[0] = state->last_code_point; /* Check if COMBINING DOT ABOVE is not yet present */ for (i = stream.current - 1; i > 0; --i) { if (stream.codepoint[i] == CP_COMBINING_DOT_ABOVE) { write_soft_dot = 0; break; } } /* Stabilize the sequence */ if (!stream.stable) { stream_reorder(&stream); stream.stable = 1; } /* Write COMBINING DOT ABOVE */ if (write_soft_dot && stream.current < STREAM_BUFFER_MAX) { /* Ensure the COMBINING DOT ABOVE comes before other accents with the same CCC */ if (stream.canonical_combining_class[stream.current - 1] == CCC_ABOVE) { unicode_t cp_swap = stream.codepoint[stream.current - 1]; stream.codepoint[stream.current - 1] = CP_COMBINING_DOT_ABOVE; stream.codepoint[stream.current] = cp_swap; } else { stream.codepoint[stream.current] = CP_COMBINING_DOT_ABOVE; } stream.canonical_combining_class[stream.current] = CCC_ABOVE; /* Check if sequence has become unstable */ stream.stable = stream.canonical_combining_class[stream.current - 1] <= CCC_ABOVE; stream.current++; } /* Write additional accent */ if (cp_additional_accent != 0 && stream.current < STREAM_BUFFER_MAX) { /* Additional accents are always of the upper variety */ stream.codepoint[stream.current] = cp_additional_accent; stream.canonical_combining_class[stream.current] = CCC_ABOVE; /* Check if sequence has become unstable */ if (stream.stable && stream.canonical_combining_class[stream.current] < stream.canonical_combining_class[stream.current - 1]) { stream.stable = 0; } stream.current++; } /* Stabilize the sequence */ if (!stream.stable) { stream_reorder(&stream); } } else { uint8_t erase_count = 0; switch (state->last_code_point) { case CP_LATIN_SMALL_LETTER_I: state->last_code_point = CP_LATIN_CAPITAL_LETTER_I; break; case CP_LATIN_SMALL_LETTER_J: state->last_code_point = CP_LATIN_CAPITAL_LETTER_J; break; case CP_LATIN_SMALL_LETTER_I_WITH_OGONEK: state->last_code_point = CP_LATIN_CAPITAL_LETTER_I_WITH_OGONEK; break; default: goto writeregular; } /* Initialize stream and read the next sequence */ if (!stream_initialize(&stream, state->src, state->src_size) || !stream_read(&stream, QuickCheckNFCIndexPtr, QuickCheckNFCDataPtr)) { goto writeregular; } /* Assign the uppercase code point to the start of the stream */ stream.codepoint[0] = state->last_code_point; /* Remove COMBINING DOT ABOVE from sequence */ for (i = 1; i < stream.current; ++i) { if (stream.codepoint[i] == CP_COMBINING_DOT_ABOVE) { stream.canonical_combining_class[i] = CCC_INVALID; erase_count++; } } /* Stabilize the sequence */ if (!stream.stable || erase_count > 0) { stream_reorder(&stream); stream.current -= erase_count; } } goto writestream; } writeregular: /* Get code point properties */ state->last_canonical_combining_class = PROPERTY_GET_CCC(state->last_code_point); state->last_general_category = PROPERTY_GET_GC(state->last_code_point); /* Move source cursor */ if (state->src_size >= state->last_code_point_size) { state->src += state->last_code_point_size; state->src_size -= state->last_code_point_size; } else { state->src_size = 0; } /* Write to output */ if (state->last_code_point_size == 1) { /* Write Basic Latin to output buffer*/ if (state->dst != 0) { if (state->dst_size < 1) { goto outofspace; } /* Uppercase letters are U+0041 ('A') to U+005A ('Z') Lowercase letters are U+0061 ('a') to U+007A ('z') */ if (state->last_code_point >= 0x41 && state->last_code_point <= 0x7A) { if (state->property_data == LowercaseDataPtr) { *state->dst = basic_latin_lowercase_table[state->last_code_point - 0x41]; } else { *state->dst = basic_latin_uppercase_table[state->last_code_point - 0x41]; } } else { /* All other code points in Basic Latin are unaffected by case mapping */ *state->dst = (char)state->last_code_point; } state->dst++; state->dst_size--; } bytes_needed = 1; } else { if (state->property_data == LowercaseDataPtr && state->last_code_point == CP_GREEK_CAPITAL_LETTER_SIGMA) { /* If the final letter of a word (defined as "a collection of code points with the General Category 'Letter'") is a GREEK CAPITAL LETTER SIGMA and more than one code point was processed, the lowercase version is U+03C2 GREEK SMALL LETTER FINAL SIGMA instead of U+03C3 GREEK SMALL LETTER SIGMA. */ /* At least one code point should have been read */ uint8_t should_convert = state->total_bytes_needed > 0; if (state->src_size > 0) { unicode_t peeked = 0; const char* peeked_src = state->src; size_t peeked_src_size = state->src_size; while (1) { uint8_t peeked_read = 0; /* Peek next code point */ if ((peeked_read = codepoint_read(peeked_src, peeked_src_size, &peeked)) == 0 || peeked_src_size < peeked_read) { should_convert = 1; break; } /* Convert if the "word" has ended */ if (PROPERTY_GET_CCC(peeked) == CCC_NOT_REORDERED) { should_convert = (PROPERTY_GET_GC(peeked) & UTF8_CATEGORY_LETTER) == 0; break; } peeked_src += peeked_read; peeked_src_size -= peeked_read; } } /* Write the converted code point to the output buffer */ bytes_needed = 2; if (state->dst != 0) { if (state->dst_size < bytes_needed) { goto outofspace; } memcpy(state->dst, should_convert ? "\xCF\x82" : "\xCF\x83", bytes_needed); state->dst += bytes_needed; state->dst_size -= bytes_needed; } return bytes_needed; } /* Check if the code point is case mapped */ qc_casemapped = PROPERTY_GET_CM(state->last_code_point); if ((qc_casemapped & state->quickcheck_flags) != 0) { /* Attempt to resolve the case mapping */ resolved = database_querydecomposition(state->last_code_point, state->property_index1, state->property_index2, state->property_data, &bytes_needed); if (resolved != 0) { /* Code point properties */ state->last_general_category = UTF8_CATEGORY_LETTER; goto writeresolvedonly; } } /* Write code point unchanged to output */ bytes_needed = codepoint_write(state->last_code_point, &state->dst, &state->dst_size); if (bytes_needed == 0) { goto outofspace; } } return bytes_needed; writeresolved: /* Move source cursor */ if (state->src_size >= state->last_code_point_size) { state->src += state->last_code_point_size; state->src_size -= state->last_code_point_size; } else { state->src_size = 0; } writeresolvedonly: /* Write resolved string to output */ if (state->dst != 0) { if (state->dst_size < bytes_needed) { goto outofspace; } memcpy(state->dst, resolved, bytes_needed); state->dst += bytes_needed; state->dst_size -= bytes_needed; } return bytes_needed; writestream: /* Get code point properties */ state->last_code_point = stream.codepoint[stream.current - 1]; state->last_canonical_combining_class = stream.canonical_combining_class[stream.current - 1]; state->last_general_category = PROPERTY_GET_GC(stream.codepoint[0]); /* Move source cursor */ state->src = stream.src; state->src_size = stream.src_size; /* Write result to the output buffer */ if (!stream_write(&stream, &state->dst, &state->dst_size, &bytes_needed)) { goto outofspace; } return bytes_needed; invaliddata: UTF8_SET_ERROR(INVALID_DATA); state->src_size = 0; return 0; outofspace: UTF8_SET_ERROR(NOT_ENOUGH_SPACE); state->src_size = 0; return 0; } ================================================ FILE: external/utf8rewind/source/internal/casemapping.h ================================================ /* Copyright (C) 2014-2016 Quinten Lansu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _UTF8REWIND_INTERNAL_CASEMAPPING_H_ #define _UTF8REWIND_INTERNAL_CASEMAPPING_H_ /*! \file \brief Case mapping interface. \cond INTERNAL */ #include "../../include/utf8rewind/utf8rewind.h" typedef struct { const char* src; char* dst; size_t src_size; size_t dst_size; size_t total_bytes_needed; unicode_t last_code_point; size_t locale; const uint32_t* property_index1; const uint32_t* property_index2; const uint32_t* property_data; uint32_t last_general_category; uint8_t last_code_point_size; uint8_t last_canonical_combining_class; uint8_t quickcheck_flags; } CaseMappingState; uint8_t casemapping_initialize( CaseMappingState* state, const char* input, size_t inputSize, char* target, size_t targetSize, const uint32_t* propertyIndex1, const uint32_t* propertyIndex2, const uint32_t* propertyData, uint8_t quickCheck, size_t locale, int32_t* errors); size_t casemapping_execute(CaseMappingState* state, int32_t* errors); /*! \endcond */ #endif /* _UTF8REWIND_INTERNAL_CASEMAPPING_H_ */ ================================================ FILE: external/utf8rewind/source/internal/codepoint.c ================================================ /* Copyright (C) 2014-2016 Quinten Lansu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "codepoint.h" const uint8_t codepoint_decoded_length[256] = { /* Basic Latin */ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x00 - 0x07 */ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x08 - 0x0F */ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x10 - 0x17 */ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x18 - 0x1F */ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x20 - 0x27 */ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x28 - 0x2F */ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x30 - 0x37 */ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x38 - 0x3F */ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x47 */ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x48 - 0x4F */ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x50 - 0x57 */ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x58 - 0x5F */ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x67 */ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x68 - 0x6F */ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x70 - 0x77 */ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x78 - 0x7F */ /* Malformed continuation byte */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x87 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x88 - 0x8F */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x97 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x98 - 0x9F */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 - 0xA7 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA8 - 0xAF */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB0 - 0xB7 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB8 - 0xBF */ /* Two bytes */ 2, 2, 2, 2, 2, 2, 2, 2, /* 0xC0 - 0xC7 */ 2, 2, 2, 2, 2, 2, 2, 2, /* 0xC8 - 0xCF */ 2, 2, 2, 2, 2, 2, 2, 2, /* 0xD0 - 0xD7 */ 2, 2, 2, 2, 2, 2, 2, 2, /* 0xD8 - 0xDF */ /* Three bytes */ 3, 3, 3, 3, 3, 3, 3, 3, /* 0xE0 - 0xE7 */ 3, 3, 3, 3, 3, 3, 3, 3, /* 0xE8 - 0xEF */ /* Four bytes */ 4, 4, 4, 4, 4, 4, 4, 4, /* 0xF0 - 0xF7 */ /* Five bytes */ 5, 5, 5, 5, /* 0xF8 - 0xFB */ /* Six bytes */ 6, 6, /* 0xFC - 0xFD */ /* Invalid */ 7, 7 /* 0xFE - 0xFF */ }; uint8_t codepoint_write(unicode_t encoded, char** target, size_t* targetSize) { uint8_t encoded_length; /* Determine encoded length of code point */ if (encoded <= MAX_BASIC_LATIN) { encoded_length = 1; } else if ( encoded <= 0x7FF) { encoded_length = 2; } else if ( encoded <= MAX_BASIC_MULTILINGUAL_PLANE) { encoded_length = 3; } else if ( encoded > MAX_LEGAL_UNICODE) { encoded = REPLACEMENT_CHARACTER; encoded_length = REPLACEMENT_CHARACTER_STRING_LENGTH; } else { encoded_length = 4; } /* Write to target */ if (*target != 0) { char* dst; if (*targetSize < encoded_length) { return 0; } dst = *target; switch (encoded_length) { case 1: *dst++ = (char)encoded; break; case 2: *dst++ = (char)(encoded >> 6) | 0xC0; *dst++ = (char)(encoded & 0x3F) | 0x80; break; case 3: *dst++ = (char)(encoded >> 12) | 0xE0; *dst++ = (char)((encoded >> 6) & 0x3F) | 0x80; *dst++ = (char)(encoded & 0x3F) | 0x80; break; case 4: *dst++ = (char)(encoded >> 18) | 0xF0; *dst++ = (char)((encoded >> 12) & 0x3F) | 0x80; *dst++ = (char)((encoded >> 6) & 0x3F) | 0x80; *dst++ = (char)(encoded & 0x3F) | 0x80; break; default: break; } *target += encoded_length; *targetSize -= encoded_length; } return encoded_length; } uint8_t codepoint_read(const char* input, size_t inputSize, unicode_t* decoded) { const uint8_t* src = (const uint8_t*)input; if (input == 0 || inputSize == 0) { /* Invalid data */ return 0; } if (*src <= MAX_BASIC_LATIN) { /* Basic Latin */ *decoded = (unicode_t)*src; return 1; } else { /* Multi-byte sequence */ static const uint8_t SequenceMask[7] = { 0x00, 0x7F, 0x1F, 0x0F, 0x07, 0x03, 0x01 }; static const unicode_t SequenceMinimum[7] = { 0x0000, 0x0000, 0x0080, 0x0800, 0x10000, MAX_LEGAL_UNICODE, MAX_LEGAL_UNICODE }; size_t src_size = inputSize; uint8_t src_index; /* Length of sequence is determined by first byte */ uint8_t decoded_length = codepoint_decoded_length[*src]; if (decoded_length < 1 || decoded_length > 6) { /* Not a multi-byte sequence starter */ *decoded = REPLACEMENT_CHARACTER; decoded_length = 1; } else if (decoded_length > 4) { /* Always an overlong sequence */ *decoded = REPLACEMENT_CHARACTER; /* All bytes in the sequence must be processed */ for (src_index = 1; src_index < decoded_length; ++src_index) { src++; /* Check if next byte is valid */ if (src_size == 0 || /* Not enough data */ (*src < 0x80 || *src > 0xBF)) /* Not a continuation byte */ { return src_index; } src_size--; } } else { /* Use mask to strip value from first byte */ *decoded = (unicode_t)(*src & SequenceMask[decoded_length]); /* All bytes in the sequence must be processed */ for (src_index = 1; src_index < decoded_length; ++src_index) { src++; /* Check if next byte is valid */ if (src_size == 0 || /* Not enough data */ (*src < 0x80 || *src > 0xBF)) /* Not a continuation byte */ { *decoded = REPLACEMENT_CHARACTER; return src_index; } src_size--; /* Add value of continuation byte to codepoint */ *decoded = (*decoded << 6) | (*src & 0x3F); } /* Check for overlong sequences and surrogate pairs */ if (*decoded < SequenceMinimum[decoded_length] || *decoded > MAX_LEGAL_UNICODE || (*decoded >= SURROGATE_HIGH_START && *decoded <= SURROGATE_LOW_END)) { *decoded = REPLACEMENT_CHARACTER; } } return decoded_length; } } ================================================ FILE: external/utf8rewind/source/internal/codepoint.h ================================================ /* Copyright (C) 2014-2016 Quinten Lansu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _UTF8REWIND_INTERNAL_CODEPOINT_H_ #define _UTF8REWIND_INTERNAL_CODEPOINT_H_ /*! \file \brief Codepoint interface. \cond INTERNAL */ #include "../../include/utf8rewind/utf8rewind.h" /*! \addtogroup internal Internal functions and definitions \{ */ /*! \def MAX_BASIC_LATIN \brief The last codepoint part of Basic Latin (U+0000 - U+007F). */ #define MAX_BASIC_LATIN 0x007F /*! \def MAX_LATIN_1 \brief The last codepoint part of Latin-1 Supplement (U+0080 - U+00FF). */ #define MAX_LATIN_1 0x00FF /*! \def MAX_BASIC_MULTILINGUAL_PLANE \brief The last legal codepoint in the Basic Multilingual Plane (BMP). */ #define MAX_BASIC_MULTILINGUAL_PLANE 0xFFFF /*! \def MAX_LEGAL_UNICODE \brief The last legal codepoint in Unicode. */ #define MAX_LEGAL_UNICODE 0x10FFFF /*! \def REPLACEMENT_CHARACTER \brief The codepoint used to replace illegal codepoints. */ #define REPLACEMENT_CHARACTER 0xFFFD /*! \def REPLACEMENT_CHARACTER_STRING \brief The replacement character as a UTF-8 encoded string. */ #define REPLACEMENT_CHARACTER_STRING "\xEF\xBF\xBD" /*! \def REPLACEMENT_CHARACTER_STRING_LENGTH \brief Length of the UTF-8 encoded string of the replacment character. */ #define REPLACEMENT_CHARACTER_STRING_LENGTH 3 /*! \def SURROGATE_HIGH_START \brief The minimum codepoint for the high member of a surrogate pair. */ #define SURROGATE_HIGH_START 0xD800 /*! \def SURROGATE_HIGH_END \brief The maximum codepoint for the high member of a surrogate pair. */ #define SURROGATE_HIGH_END 0xDBFF /*! \def SURROGATE_LOW_START \brief The minimum codepoint for the low member of a surrogate pair. */ #define SURROGATE_LOW_START 0xDC00 /*! \def SURROGATE_LOW_END \brief The maximum codepoint for the low member of a surrogate pair. */ #define SURROGATE_LOW_END 0xDFFF /*! \def HANGUL_JAMO_FIRST \brief The first codepoint part of the Hangul Jamo block. */ #define HANGUL_JAMO_FIRST 0x1100 /*! \def HANGUL_JAMO_LAST \brief The last codepoint part of the Hangul Jamo block. */ #define HANGUL_JAMO_LAST 0x11FF /*! \def HANGUL_L_FIRST \brief The first codepoint part of the Hangul Jamo L section used for normalization. */ #define HANGUL_L_FIRST 0x1100 /*! \def HANGUL_L_LAST \brief The last codepoint part of the Hangul Jamo L section used for normalization. */ #define HANGUL_L_LAST 0x1112 /*! \def HANGUL_L_COUNT \brief The number of codepoints in the Hangul Jamo L section. */ #define HANGUL_L_COUNT 19 /*! \def HANGUL_V_FIRST \brief The first codepoint part of the Hangul Jamo V section used for normalization. */ #define HANGUL_V_FIRST 0x1161 /*! \def HANGUL_V_LAST \brief The last codepoint part of the Hangul Jamo V section used for normalization. */ #define HANGUL_V_LAST 0x1175 /*! \def HANGUL_V_COUNT \brief The number of codepoints in the Hangul Jamo V section. */ #define HANGUL_V_COUNT 21 /*! \def HANGUL_T_FIRST \brief The first codepoint part of the Hangul Jamo T section used for normalization. */ #define HANGUL_T_FIRST 0x11A7 /*! \def HANGUL_T_LAST \brief The last codepoint part of the Hangul Jamo V section used for normalization. */ #define HANGUL_T_LAST 0x11C2 /*! \def HANGUL_T_COUNT \brief The number of codepoints in the Hangul Jamo T section. */ #define HANGUL_T_COUNT 28 /*! \def HANGUL_N_COUNT \brief Number of codepoints part of the Hangul Jamo V and T sections. */ #define HANGUL_N_COUNT 588 /* VCount * TCount */ /*! \def HANGUL_S_FIRST \brief The first codepoint in the Hangul Syllables block. */ #define HANGUL_S_FIRST 0xAC00 /*! \def HANGUL_S_LAST \brief The last codepoint in the Hangul Syllables block. */ #define HANGUL_S_LAST 0xD7A3 /*! \def HANGUL_S_COUNT \brief The number of codepoints in the Hangul Syllables block. */ #define HANGUL_S_COUNT 11172 /* LCount * NCount */ #define CP_LATIN_CAPITAL_LETTER_I 0x0049 #define CP_LATIN_CAPITAL_LETTER_J 0x004A #define CP_LATIN_SMALL_LETTER_I 0x0069 #define CP_LATIN_SMALL_LETTER_J 0x006A #define CP_LATIN_CAPITAL_LETTER_I_WITH_GRAVE 0x00CC #define CP_LATIN_CAPITAL_LETTER_I_WITH_ACUTE 0x00CD #define CP_LATIN_CAPITAL_LETTER_I_WITH_TILDE 0x0128 #define CP_LATIN_CAPITAL_LETTER_I_WITH_OGONEK 0x012E #define CP_LATIN_SMALL_LETTER_I_WITH_OGONEK 0x012F #define CP_LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE 0x0130 #define CP_LATIN_SMALL_LETTER_DOTLESS_I 0x0131 #define CP_COMBINING_GRAVE_ACCENT 0x0300 #define CP_COMBINING_ACUTE_ACCENT 0x0301 #define CP_COMBINING_TILDE_ACCENT 0x0303 #define CP_COMBINING_DOT_ABOVE 0x0307 #define CP_COMBINING_GREEK_YPOGEGRAMMENI 0x0345 #define CP_COMBINING_GRAPHEME_JOINER 0x034F #define CP_GREEK_CAPITAL_LETTER_SIGMA 0x03A3 #define CCC_NOT_REORDERED 0 #define CCC_OVERLAY 1 #define CCC_NUKTA 7 #define CCC_KANA_VOICING 8 #define CCC_VIRAMA 9 #define CCC_FIXED_POSITION_START 10 #define CCC_FIXED_POSITION_END 199 #define CCC_ATTACHED_BELOW_LEFT 200 #define CCC_ATTACHED_BELOW 202 #define CCC_ATTACHED_BOTTOM_RIGHT 204 #define CCC_ATTACHED_LEFT 208 #define CCC_ATTACHED_RIGHT 210 #define CCC_ATTACHED_TOP_LEFT 212 #define CCC_ATTACHED_ABOVE 214 #define CCC_ATTACHED_ABOVE_RIGHT 216 #define CCC_BELOW_LEFT 218 #define CCC_BELOW 220 #define CCC_BELOW_RIGHT 222 #define CCC_LEFT 224 #define CCC_RIGHT 226 #define CCC_ABOVE_LEFT 228 #define CCC_ABOVE 230 #define CCC_ABOVE_RIGHT 232 #define CCC_DOUBLE_BELOW 233 #define CCC_DOUBLE_ABOVE 234 #define CCC_IOTA_SUBSCRIPT 240 #define CCC_INVALID 255 /*! \brief Get the number of bytes used for encoding a code point. \param[in] byte Encoded byte \return Number of bytes needed for decoding or 0 if input is illegal. */ extern const uint8_t codepoint_decoded_length[256]; /*! \brief Write Unicode code point to UTF-8 encoded string. Target buffer and size is modified by encoded size. \param[in] encoded Unicode code point \param[in,out] target Target buffer \param[in,out] targetSize Size of output buffer in bytes \return Bytes needed for encoding or 0 on error. */ uint8_t codepoint_write(unicode_t encoded, char** target, size_t* targetSize); /*! \brief Read Unicode code point from UTF-8 encoded string. \param[in] input Input buffer \param[in] inputSize Size of input buffer in bytes \param[out] decoded Unicode codepoint \return Bytes read from string or 0 on error. */ uint8_t codepoint_read(const char* input, size_t inputSize, unicode_t* decoded); /*! \} */ /*! \endcond */ #endif /* _UTF8REWIND_INTERNAL_CODEPOINT_H_ */ ================================================ FILE: external/utf8rewind/source/internal/composition.c ================================================ /* Copyright (C) 2014-2016 Quinten Lansu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "composition.h" #include "codepoint.h" #include "database.h" uint8_t compose_initialize(ComposeState* state, StreamState* input, StreamState* output, uint8_t compatibility) { memset(state, 0, sizeof(ComposeState)); /* Ensure streams are valid */ if (input == 0 || output == 0) { return 0; } /* Set up streams */ state->input = input; state->output = output; memset(state->output, 0, sizeof(StreamState)); /* Set up codepoint quickcheck property */ if (compatibility == 1) { state->qc_index = QuickCheckNFKCIndexPtr; state->qc_data = QuickCheckNFKCDataPtr; } else { state->qc_index = QuickCheckNFCIndexPtr; state->qc_data = QuickCheckNFCDataPtr; } return 1; } uint8_t compose_readcodepoint(ComposeState* state, uint8_t index) { if (state->input->index == state->input->current && !stream_read(state->input, state->qc_index, state->qc_data)) { /* End of data */ return 0; } /* Get next codepoint from sequence */ state->output->codepoint[index] = state->input->codepoint[state->input->index]; state->output->quick_check[index] = state->input->quick_check[state->input->index]; state->output->canonical_combining_class[index] = state->input->canonical_combining_class[state->input->index]; state->input->index++; state->output->current++; return 1; } uint8_t compose_execute(ComposeState* state) { uint8_t output_index; uint8_t cursor_current; uint8_t cursor_next; /* Check if input is available */ if (state->input == 0) { return 0; } /* Reset output */ state->output->current = 0; /* Read first codepoint */ if (!compose_readcodepoint(state, 0)) { return 0; } for (output_index = 0; output_index < state->output->current; ++output_index) { /* Ensure current codepoint is a starter */ cursor_current = output_index; while (state->output->canonical_combining_class[cursor_current] != CCC_NOT_REORDERED) { cursor_current++; if (cursor_current == state->output->current && !compose_readcodepoint(state, cursor_current)) { /* Only non-starters left */ return 1; } } /* Get next codepoint */ cursor_next = cursor_current + 1; while ( cursor_next < state->output->current || compose_readcodepoint(state, cursor_next)) { /* Two codepoints can be composed if the current codepoint is a starter and the next codepoint isn't blocked by a previous codepoint. */ if (state->output->canonical_combining_class[cursor_next] > state->output->canonical_combining_class[cursor_next - 1] || /* Can be composed based on CCC */ /* Quick check value can override composition block by previous codepoint */ (state->output->quick_check[cursor_next] != QuickCheckResult_Yes && state->output->canonical_combining_class[cursor_next - 1] == CCC_NOT_REORDERED)) { unicode_t composed = 0; /* Hangul composition Algorithm adapted from Unicode Technical Report #15: http://www.unicode.org/reports/tr15/tr15-18.html#Hangul */ if (state->output->codepoint[cursor_current] >= HANGUL_L_FIRST && state->output->codepoint[cursor_current] <= HANGUL_L_LAST) { /* Check for Hangul LV pair */ if (state->output->codepoint[cursor_next] >= HANGUL_V_FIRST && state->output->codepoint[cursor_next] <= HANGUL_V_LAST) { unicode_t l_index = state->output->codepoint[cursor_current] - HANGUL_L_FIRST; unicode_t v_index = state->output->codepoint[cursor_next] - HANGUL_V_FIRST; composed = HANGUL_S_FIRST + (((l_index * HANGUL_V_COUNT) + v_index) * HANGUL_T_COUNT); } } else if ( state->output->codepoint[cursor_current] >= HANGUL_S_FIRST && state->output->codepoint[cursor_current] <= HANGUL_S_LAST) { /* Check for Hangul LV and T pair */ if (state->output->codepoint[cursor_next] >= HANGUL_T_FIRST && state->output->codepoint[cursor_next] <= HANGUL_T_LAST) { unicode_t t_index = state->output->codepoint[cursor_next] - HANGUL_T_FIRST; composed = state->output->codepoint[cursor_current] + t_index; } } else { /* Attempt to compose codepoints using the database */ composed = database_querycomposition( state->output->codepoint[cursor_current], state->output->codepoint[cursor_next]); } /* Check if composition succeeded */ if (composed != 0) { /* When we successfully compose two codepoints, the second must be removed from the sequence. The way this is accomplished is by marking the cell empty with a NUL codepoint. Decomposed: codepoint U+0044 U+0307 U+0031 index 0 1 2 Composed: codepoint U+1E0A U+0000 U+0031 index 0 1 2 If the second codepoint was at the end of the sequence, the output sequence is shortened by one. */ /* Add composition to output */ state->output->codepoint[cursor_current] = composed; state->output->quick_check[cursor_current] = PROPERTY_GET(state->qc_index, state->qc_data, composed); state->output->canonical_combining_class[cursor_current] = PROPERTY_GET_CCC(composed); /* Clear next codepoint from output */ state->output->codepoint[cursor_next] = 0; state->output->quick_check[cursor_next] = QuickCheckResult_Yes; state->output->canonical_combining_class[cursor_next] = CCC_NOT_REORDERED; if (cursor_next == state->output->current - 1) { /* Next codepoint was at end of output */ state->output->current--; } /* Reset cursor to current output index */ cursor_current = output_index; cursor_next = output_index; } } else if ( state->output->canonical_combining_class[cursor_next] == CCC_NOT_REORDERED) { /* Attempt to compose starters, but do not read from the next sequence */ break; } /* Evaluate next codepoint */ cursor_next++; } /* Fill up "holes" left by composing codepoints not at the end of the sequence */ if (state->output->current > 1) { uint8_t write_index = 0; uint8_t read_index = 1; /* We want to move valid codepoints to the left as much as possible in order to fill up holes left by the composition process. Note that the process does not clear unused codepoints at the end, this is a small optimization in order to avoid unnecessary clears. The length member is adjusted to the new size. Before reordering: codepoint A B 0 0 0 D index 0 1 2 3 4 5 length 6 After reordering: codepoint A B D 0 0 D index 0 1 2 3 4 5 length 3 */ /* Evaluate all codepoints in output sequence */ while (write_index < state->output->current) { /* Check if read cursor is on an empty cell */ if (read_index < state->output->current && state->output->codepoint[read_index] == 0) { /* Skip all empty cells */ while ( read_index < state->output->current && state->output->codepoint[read_index] == 0) { read_index++; } if (read_index == state->output->current) { /* Reached end of data */ break; } /* Copy cell at read cursor to write cursor */ state->output->codepoint[write_index] = state->output->codepoint[read_index]; state->output->quick_check[write_index] = state->output->quick_check[read_index]; state->output->canonical_combining_class[write_index] = state->output->canonical_combining_class[read_index]; } /* Move cursors */ write_index++; read_index++; } /* Adjust length of output sequence */ state->output->current = write_index; } else { /* Evaluated all sequences in output */ state->input = 0; break; } } return 1; } ================================================ FILE: external/utf8rewind/source/internal/composition.h ================================================ /* Copyright (C) 2014-2016 Quinten Lansu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _UTF8REWIND_INTERNAL_COMPOSITION_H_ #define _UTF8REWIND_INTERNAL_COMPOSITION_H_ /*! \file \brief Composition interface. \cond INTERNAL */ #include "../../include/utf8rewind/utf8rewind.h" #include "streaming.h" typedef struct { StreamState* input; StreamState* output; const size_t* qc_index; const uint8_t* qc_data; } ComposeState; uint8_t compose_initialize(ComposeState* state, StreamState* input, StreamState* output, uint8_t compatibility); uint8_t compose_readcodepoint(ComposeState* state, uint8_t index); uint8_t compose_execute(ComposeState* state); /*! \endcond */ #endif /* _UTF8REWIND_INTERNAL_COMPOSITION_H_ */ ================================================ FILE: external/utf8rewind/source/internal/database.c ================================================ /* Copyright (C) 2014-2016 Quinten Lansu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "database.h" #include "../unicodedatabase.h" #include "codepoint.h" #define DECOMPOSE_INDEX1_SHIFT (12) #define DECOMPOSE_INDEX2_SHIFT (5) static const unicode_t DECOMPOSE_INDEX1_MASK = MAX_LEGAL_UNICODE; static const unicode_t DECOMPOSE_INDEX2_MASK = (1 << DECOMPOSE_INDEX1_SHIFT) - 1; static const unicode_t DECOMPOSE_DATA_MASK = (1 << DECOMPOSE_INDEX2_SHIFT) - 1; const char* database_querydecomposition(unicode_t codepoint, const uint32_t* index1Array, const uint32_t* index2Array, const uint32_t* dataArray, uint8_t* length) { uint32_t index; uint32_t data; index = index1Array[codepoint >> DECOMPOSE_INDEX1_SHIFT]; index = index2Array[index + ((codepoint & DECOMPOSE_INDEX2_MASK) >> DECOMPOSE_INDEX2_SHIFT)]; index = index + (codepoint & DECOMPOSE_DATA_MASK); if (index == 0 || (data = dataArray[index]) == 0) { *length = 0; return 0; } *length = (uint8_t)((data & 0xFF000000) >> 24); return CompressedStringData + (data & 0x00FFFFFF); } unicode_t database_querycomposition(unicode_t left, unicode_t right) { uint64_t key = ((uint64_t)left << 32) + (uint64_t)right; size_t offset_start = 0; size_t offset_end = UnicodeCompositionRecordCount - 1; size_t offset_pivot; size_t i; if (key < UnicodeCompositionRecordPtr[offset_start].key || key > UnicodeCompositionRecordPtr[offset_end].key) { return 0; } do { offset_pivot = offset_start + ((offset_end - offset_start) / 2); if (key == UnicodeCompositionRecordPtr[offset_start].key) { return UnicodeCompositionRecordPtr[offset_start].value; } else if (key == UnicodeCompositionRecordPtr[offset_end].key) { return UnicodeCompositionRecordPtr[offset_end].value; } else if (key == UnicodeCompositionRecordPtr[offset_pivot].key) { return UnicodeCompositionRecordPtr[offset_pivot].value; } else { if (key > UnicodeCompositionRecordPtr[offset_pivot].key) { offset_start = offset_pivot; } else { offset_end = offset_pivot; } } } while (offset_end - offset_start > 32); for (i = offset_start; i <= offset_end; ++i) { if (key == UnicodeCompositionRecordPtr[i].key) { return UnicodeCompositionRecordPtr[i].value; } } return 0; } ================================================ FILE: external/utf8rewind/source/internal/database.h ================================================ /* Copyright (C) 2014-2016 Quinten Lansu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _UTF8REWIND_INTERNAL_DATABASE_H_ #define _UTF8REWIND_INTERNAL_DATABASE_H_ /*! \file \brief Database interface. \cond INTERNAL */ #include "../../include/utf8rewind/utf8rewind.h" #include "../unicodedatabase.h" enum QuickCheckCaseMapped { QuickCheckCaseMapped_Uppercase = 0x01, QuickCheckCaseMapped_Lowercase = 0x02, QuickCheckCaseMapped_Titlecase = 0x04, QuickCheckCaseMapped_Casefolded = 0x08, }; enum QuickCheckResult { QuickCheckResult_Yes, QuickCheckResult_Maybe, QuickCheckResult_No, }; #define PROPERTY_INDEX_SHIFT (5) static const unicode_t PROPERTY_DATA_MASK = (1 << PROPERTY_INDEX_SHIFT) - 1; #define PROPERTY_GET(_indexArray, _dataArray, _cp) \ (_dataArray)[ \ (_indexArray)[(_cp) >> PROPERTY_INDEX_SHIFT] + \ ((_cp) & PROPERTY_DATA_MASK)] #define PROPERTY_GET_GC(_cp) \ PROPERTY_GET(GeneralCategoryIndexPtr, GeneralCategoryDataPtr, _cp) #define PROPERTY_GET_CCC(_cp) \ PROPERTY_GET(CanonicalCombiningClassIndexPtr, CanonicalCombiningClassDataPtr, _cp) #define PROPERTY_GET_CM(_cp) \ PROPERTY_GET(QuickCheckCaseMappedIndexPtr, QuickCheckCaseMappedDataPtr, _cp) #define PROPERTY_GET_NFC(_cp) \ PROPERTY_GET(QuickCheckNFCIndexPtr, QuickCheckNFCDataPtr, _cp) #define PROPERTY_GET_NFD(_cp) \ PROPERTY_GET(QuickCheckNFDIndexPtr, QuickCheckNFDDataPtr, _cp) #define PROPERTY_GET_NFKC(_cp) \ PROPERTY_GET(QuickCheckNFKCIndexPtr, QuickCheckNFKCDataPtr, _cp) #define PROPERTY_GET_NFKD(_cp) \ PROPERTY_GET(QuickCheckNFKDIndexPtr, QuickCheckNFKDDataPtr, _cp) const char* database_querydecomposition(unicode_t codepoint, const uint32_t* index1Array, const uint32_t* index2Array, const uint32_t* dataArray, uint8_t* length); unicode_t database_querycomposition(unicode_t left, unicode_t right); /*! \endcond */ #endif /* _UTF8REWIND_INTERNAL_DATABASE_H_ */ ================================================ FILE: external/utf8rewind/source/internal/decomposition.c ================================================ /* Copyright (C) 2014-2016 Quinten Lansu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "decomposition.h" #include "codepoint.h" #include "database.h" uint8_t decompose_initialize( DecomposeState* state, StreamState* input, StreamState* output, uint8_t compatibility) { memset(state, 0, sizeof(DecomposeState)); /* Ensure streams are valid */ if (input == 0 || output == 0) { return 0; } /* Set up streams */ state->input = input; state->output = output; memset(state->output, 0, sizeof(StreamState)); /* Set up codepoint quickcheck property */ if (compatibility == 1) { state->property_index1 = NFKDIndex1Ptr; state->property_index2 = NFKDIndex2Ptr; state->property_data = NFKDDataPtr; state->qc_index = QuickCheckNFKDIndexPtr; state->qc_data = QuickCheckNFKDDataPtr; } else { state->property_index1 = NFDIndex1Ptr; state->property_index2 = NFDIndex2Ptr; state->property_data = NFDDataPtr; state->qc_index = QuickCheckNFDIndexPtr; state->qc_data = QuickCheckNFDDataPtr; } return 1; } uint8_t decompose_execute(DecomposeState* state) { unicode_t* src_codepoint; unicode_t* dst_codepoint; uint8_t* dst_canonical_combining_class; uint8_t* dst_quick_check; uint8_t uncached = 1; /* Check if input is valid */ if (state->input == 0) { return 0; } /* Set up output */ state->output->current = 0; state->output->index = 0; state->output->stable = 1; dst_codepoint = state->output->codepoint; dst_canonical_combining_class = state->output->canonical_combining_class; dst_quick_check = state->output->quick_check; /* Check cache for stored sequences */ if (state->cache_current < state->cache_filled) { /* Read from cache */ while (state->cache_current < state->cache_filled) { if (state->output->current > 0 && state->cache_canonical_combining_class[state->cache_current] == CCC_NOT_REORDERED) { /* Sequence ends on next non-starter or end of data */ break; } *dst_codepoint++ = state->cache_codepoint[state->cache_current]; *dst_canonical_combining_class++ = state->cache_canonical_combining_class[state->cache_current]; *dst_quick_check++ = QuickCheckResult_Yes; state->output->current++; state->cache_current++; } /* Check if cache has been emptied */ if (state->cache_current == state->cache_filled) { state->cache_current = 0; state->cache_filled = 0; } /* Check for additional input */ if (state->input->index == state->input->current) { /* Don't compare canonical combining classes, output will always be stable */ return state->output->current; } } /* Read next sequence from input */ if (state->input->index == state->input->current && !stream_read(state->input, state->qc_index, state->qc_data)) { /* End of data */ state->input = 0; return 0; } /* Read from source */ src_codepoint = state->input->codepoint + state->input->index; while (state->input->index < state->input->current) { if (*src_codepoint <= MAX_BASIC_LATIN) { /* Basic Latin codepoints are already decomposed */ if (uncached) { *dst_codepoint++ = *src_codepoint; *dst_canonical_combining_class++ = CCC_NOT_REORDERED; *dst_quick_check++ = QuickCheckResult_Yes; state->output->current++; } else { state->cache_codepoint[state->cache_filled] = *src_codepoint; state->cache_canonical_combining_class[state->cache_filled] = CCC_NOT_REORDERED; state->cache_filled++; } } else if ( *src_codepoint >= HANGUL_S_FIRST && *src_codepoint <= HANGUL_S_LAST) { /* Hangul decomposition Algorithm adapted from Unicode Technical Report #15: http://www.unicode.org/reports/tr15/tr15-18.html#Hangul */ unicode_t s_index = *src_codepoint - HANGUL_S_FIRST; if (uncached) { *dst_codepoint++ = HANGUL_L_FIRST + (s_index / HANGUL_N_COUNT); *dst_canonical_combining_class++ = CCC_NOT_REORDERED; *dst_quick_check++ = QuickCheckResult_Yes; state->output->current++; } else { state->cache_codepoint[state->cache_filled] = HANGUL_L_FIRST + (s_index / HANGUL_N_COUNT); state->cache_canonical_combining_class[state->cache_filled] = CCC_NOT_REORDERED; state->cache_filled++; } /* Store subsequent non-starters in cache */ uncached = 0; state->cache_codepoint[state->cache_filled] = HANGUL_V_FIRST + (s_index % HANGUL_N_COUNT) / HANGUL_T_COUNT; state->cache_canonical_combining_class[state->cache_filled] = CCC_NOT_REORDERED; state->cache_filled++; if ((s_index % HANGUL_T_COUNT) != 0) { state->cache_codepoint[state->cache_filled] = HANGUL_T_FIRST + (s_index % HANGUL_T_COUNT); state->cache_canonical_combining_class[state->cache_filled] = CCC_NOT_REORDERED; state->cache_filled++; } } else { /* Use quick check to skip stable codepoints */ unicode_t decoded_codepoint = *src_codepoint; uint8_t decoded_quick_check = PROPERTY_GET(state->qc_index, state->qc_data, decoded_codepoint); uint8_t decoded_canonical_combining_class; uint8_t decoded_size; if (decoded_quick_check != QuickCheckResult_Yes) { /* Check database for decomposition */ uint8_t src_size; const char* src = database_querydecomposition( decoded_codepoint, state->property_index1, state->property_index2, state->property_data, &src_size); while (src_size > 0) { /* Decode current codepoint */ decoded_size = codepoint_read(src, src_size, &decoded_codepoint); if (decoded_size == 0) { break; } decoded_canonical_combining_class = PROPERTY_GET_CCC(decoded_codepoint); /* Check for end of sequence */ if (uncached && state->output->current > 0 && decoded_canonical_combining_class == CCC_NOT_REORDERED) { uncached = 0; } if (uncached) { /* Write codepoint to output */ *dst_codepoint++ = decoded_codepoint; *dst_canonical_combining_class++ = decoded_canonical_combining_class; *dst_quick_check++ = QuickCheckResult_Yes; state->output->current++; } else { /* Store in cache */ state->cache_codepoint[state->cache_filled] = decoded_codepoint; state->cache_canonical_combining_class[state->cache_filled] = decoded_canonical_combining_class; state->cache_filled++; } src += decoded_size; src_size -= decoded_size; } } else { decoded_canonical_combining_class = PROPERTY_GET_CCC(decoded_codepoint); if (uncached) { /* Write codepoint to output */ *dst_codepoint++ = decoded_codepoint; *dst_canonical_combining_class++ = decoded_canonical_combining_class; *dst_quick_check++ = decoded_quick_check; state->output->current++; } else { /* Store in cache */ state->cache_codepoint[state->cache_filled] = decoded_codepoint; state->cache_canonical_combining_class[state->cache_filled] = decoded_canonical_combining_class; state->cache_filled++; } } } src_codepoint++; state->input->index++; } if (state->output->current > 1) { /* Check if output is stable by comparing canonical combining classes */ uint8_t i; for (i = 1; i < state->output->current; ++i) { if (state->output->canonical_combining_class[i] < state->output->canonical_combining_class[i - 1]) { state->output->stable = 0; break; } } } return state->output->current; } ================================================ FILE: external/utf8rewind/source/internal/decomposition.h ================================================ /* Copyright (C) 2014-2016 Quinten Lansu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _UTF8REWIND_INTERNAL_DECOMPOSITION_H_ #define _UTF8REWIND_INTERNAL_DECOMPOSITION_H_ /*! \file \brief Decomposition interface. \cond INTERNAL */ #include "../../include/utf8rewind/utf8rewind.h" #include "streaming.h" typedef struct { StreamState* input; StreamState* output; const size_t* qc_index; const uint8_t* qc_data; const uint32_t* property_index1; const uint32_t* property_index2; const uint32_t* property_data; unicode_t cache_codepoint[STREAM_BUFFER_MAX]; uint8_t cache_canonical_combining_class[STREAM_BUFFER_MAX]; uint8_t cache_current; uint8_t cache_filled; } DecomposeState; uint8_t decompose_initialize(DecomposeState* state, StreamState* input, StreamState* output, uint8_t compatibility); uint8_t decompose_execute(DecomposeState* state); /*! \endcond */ #endif /* _UTF8REWIND_INTERNAL_DECOMPOSITION_H_ */ ================================================ FILE: external/utf8rewind/source/internal/seeking.c ================================================ /* Copyright (C) 2014-2016 Quinten Lansu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "seeking.h" #include "codepoint.h" const char* seeking_forward(const char* input, const char* inputEnd, size_t inputSize, off_t offset) { if (inputEnd <= input || /* Swapped parameters */ offset <= 0 || /* Invalid offset */ inputSize == 0) /* Nothing to do */ { return input; } else if ( offset >= (off_t)inputSize) /* Out of bounds */ { return inputEnd; } do { /* Get decoded length of next sequence */ uint8_t codepoint_length = codepoint_decoded_length[(uint8_t)*input]; if (codepoint_length > 1 && codepoint_length < 7) { /* Check all bytes of multi-byte sequence */ uint8_t i; for (i = 0; i < codepoint_length; ++i) { /* Next byte of sequence */ input++; if (input == inputEnd || /* End of data */ codepoint_decoded_length[(uint8_t)*input] != 0) /* Not a continuation byte */ { break; } } } else { /* Skip to next sequence */ input++; } } while (input < inputEnd && --offset > 0); return input; } const char* seeking_rewind(const char* inputStart, const char* input, size_t inputSize, off_t offset) { const char* marker; const char* marker_valid; if (inputStart >= input || /* Swapped parameters */ offset >= 0) /* Invalid offset */ { return input; } else if ( -offset >= (off_t)inputSize) /* Out of bounds */ { return inputStart; } /* Set up the marker */ marker = input - 1; marker_valid = marker; do { /* Move the cursor */ input--; /* Move the marker until we encounter a valid sequence */ while (marker_valid == input) { uint8_t codepoint_length = codepoint_decoded_length[(uint8_t)*marker]; if (codepoint_length == 1 || /* Basic Latin */ codepoint_length == 7) /* Illegal byte */ { marker_valid = marker; break; } else if ( codepoint_length > 1) { if (marker == inputStart && /* Not overlong */ marker_valid - inputStart == codepoint_length - 1) { /* Last sequence */ return marker; } else { /* Multi-byte sequence */ marker_valid = marker + codepoint_length - 1; break; } } else if ( marker <= inputStart) { /* Continuation bytes only */ marker_valid = marker; break; } else { /* Move marker to next byte */ marker--; } } /* Read the next part of a sequence */ if (input <= marker_valid) { if (marker == inputStart) { /* Last sequence */ return marker; } else { /* Move the cursor to the start of the sequence */ input = marker; /* Reset the marker on the next byte */ marker--; marker_valid = marker; } } } while (input >= inputStart && ++offset < 0); return input; } ================================================ FILE: external/utf8rewind/source/internal/seeking.h ================================================ /* Copyright (C) 2014-2016 Quinten Lansu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _UTF8REWIND_INTERNAL_SEEKING_H_ #define _UTF8REWIND_INTERNAL_SEEKING_H_ /*! \file \brief Seeking interface. \cond INTERNAL */ #include "../../include/utf8rewind/utf8rewind.h" const char* seeking_forward(const char* input, const char* inputEnd, size_t inputSize, off_t offset); const char* seeking_rewind(const char* inputStart, const char* input, size_t inputSize, off_t offset); /*! \endcond */ #endif /* _UTF8REWIND_INTERNAL_SEEKING_H_ */ ================================================ FILE: external/utf8rewind/source/internal/streaming.c ================================================ /* Copyright (C) 2014-2016 Quinten Lansu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "streaming.h" #include "codepoint.h" #include "database.h" uint8_t stream_initialize(StreamState* state, const char* input, size_t inputSize) { memset(state, 0, sizeof(StreamState)); if (input == 0 || inputSize == 0) { return 0; } state->src = input; state->src_size = inputSize; state->stable = 1; return 1; } uint8_t stream_read(StreamState* state, const size_t* propertyIndex, const uint8_t* propertyData) { /* Ensure input is available */ if (state->src_size == 0 || propertyIndex == 0 || propertyData == 0) { return 0; } /* Reset sequence after the first pass */ if (state->filled > 0) { /* Check for end of data */ if (state->filled == state->current && state->src_size <= state->last_length) { state->src_size = 0; state->index = 0; state->current = 0; state->filled = 0; return 0; } /* Copy last peeked codepoint to new sequence */ state->codepoint[0] = state->codepoint[state->filled - 1]; state->canonical_combining_class[0] = state->canonical_combining_class[state->filled - 1]; state->quick_check[0] = state->quick_check[state->filled - 1]; /* New sequence always starts as stable */ state->stable = 1; /* Reset buffer members */ state->index = 0; state->current = 1; state->filled = 1; } /* Read codepoints */ while (state->filled < STREAM_SAFE_MAX) { /* Move the input cursor after peeking */ if (state->last_length > 0) { if (state->src_size <= state->last_length) { state->src += state->src_size; state->src_size = 0; break; } state->src += state->last_length; state->src_size -= state->last_length; } /* Peek the next codepoint */ state->last_length = codepoint_read(state->src, state->src_size, &state->codepoint[state->filled]); state->quick_check[state->filled] = PROPERTY_GET(propertyIndex, propertyData, state->codepoint[state->filled]); state->canonical_combining_class[state->filled] = PROPERTY_GET_CCC(state->codepoint[state->filled]); state->filled++; if (state->current > 0) { /* Sequences end on the next starter and can consist of only non-starters */ if (state->canonical_combining_class[state->current] == 0) { break; } /* Check if sequence is unstable by comparing canonical combining classes */ if (state->stable && state->canonical_combining_class[state->current] < state->canonical_combining_class[state->current - 1]) { state->stable = 0; } } state->current++; } if (state->filled == STREAM_SAFE_MAX) { /* Insert COMBINING GRAPHEME JOINER into output */ state->codepoint[state->filled] = CP_COMBINING_GRAPHEME_JOINER; state->quick_check[state->filled] = QuickCheckResult_Yes; state->canonical_combining_class[state->filled] = CCC_NOT_REORDERED; state->filled++; } return 1; } uint8_t stream_write(StreamState* state, char** output, size_t* outputSize, uint8_t* bytesWritten) { uint8_t i; if (state->current == 0) { /* Nothing to write */ *bytesWritten = 0; return 1; } /* Encode code points as UTF-8 */ for (i = 0; i < state->current; ++i) { uint8_t encoded_size = codepoint_write(state->codepoint[i], output, outputSize); if (encoded_size == 0) { /* Not enough space */ return 0; } *bytesWritten += encoded_size; } return 1; } uint8_t stream_reorder(StreamState* state) { uint8_t i; uint8_t dirty = 1; if (state->current == 0) { /* Nothing to do */ return 0; } /* Reorder codepoints until the entire sequence is table */ do { dirty = 0; for (i = 1; i < state->current; i++) { /* Sort codepoints by canonical combining class, smallest to largest */ if (state->canonical_combining_class[i] < state->canonical_combining_class[i - 1]) { unicode_t swap_cp; uint8_t swap_qc; uint8_t swap_ccc; swap_cp = state->codepoint[i]; state->codepoint[i] = state->codepoint[i - 1]; state->codepoint[i - 1] = swap_cp; swap_qc = state->quick_check[i]; state->quick_check[i] = state->quick_check[i - 1]; state->quick_check[i - 1] = swap_qc; swap_ccc = state->canonical_combining_class[i]; state->canonical_combining_class[i] = state->canonical_combining_class[i - 1]; state->canonical_combining_class[i - 1] = swap_ccc; dirty = 1; } } } while (dirty == 1); return 1; } ================================================ FILE: external/utf8rewind/source/internal/streaming.h ================================================ /* Copyright (C) 2014-2016 Quinten Lansu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _UTF8REWIND_INTERNAL_STREAMING_H_ #define _UTF8REWIND_INTERNAL_STREAMING_H_ /*! \file \brief Streaming interface. \cond INTERNAL */ #include "../../include/utf8rewind/utf8rewind.h" /* UAX15-D4. Stream-Safe Text Process This is the process of producing a Unicode string in Stream-Safe Text Format by processing that string from start to finish, inserting U+034F COMBINING GRAPHEME JOINER (CGJ) within long sequences of non-starters. The exact position of the inserted CGJs are determined according to the following algorithm, which describes the generation of an output string from an input string: * If the input string is empty, return an empty output string. * Set nonStarterCount to zero. * For each code point C in the input string: * Produce the NFKD decomposition S. * If nonStarterCount plus the number of initial non-starters in S is greater than 30, append a CGJ to the output string and set the nonStarterCount to zero. * Append C to the output string. * If there are no starters in S, increment nonStarterCount by the number of code points in S; otherwise, set nonStarterCount to the number of trailing non-starters in S (which may be zero). * Return the output string. */ #define STREAM_SAFE_MAX 30 #define STREAM_BUFFER_MAX 32 typedef struct { const char* src; size_t src_size; uint8_t index; uint8_t current; uint8_t filled; uint8_t stable; uint8_t last_length; unicode_t codepoint[STREAM_BUFFER_MAX]; uint8_t quick_check[STREAM_BUFFER_MAX]; uint8_t canonical_combining_class[STREAM_BUFFER_MAX]; } StreamState; uint8_t stream_initialize(StreamState* state, const char* input, size_t inputSize); uint8_t stream_read(StreamState* state, const size_t* propertyIndex, const uint8_t* propertyData); uint8_t stream_write(StreamState* state, char** output, size_t* outputSize, uint8_t* bytesWritten); uint8_t stream_reorder(StreamState* state); /*! \endcond */ #endif /* _UTF8REWIND_INTERNAL_STREAMING_H_ */ ================================================ FILE: external/utf8rewind/source/unicodedatabase.c ================================================ /* Copyright (C) 2014-2016 Quinten Lansu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* DO NOT MODIFY, AUTO-GENERATED Generated on: 2016-02-01T14:10:25 Command line: tools\converter\unicodedata.py */ #include "unicodedatabase.h" const size_t GeneralCategoryIndex[34816] = { 0, 32, 64, 96, 0, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 224, 480, 512, 544, 576, 608, 640, 672, 704, 704, 704, 736, 768, 800, 832, 864, 896, 928, 527, 224, 960, 224, 992, 224, 224, 1024, 1056, 1088, 1120, 1152, 1184, 1216, 1248, 1280, 1312, 1344, 1280, 1280, 1376, 1408, 1440, 1472, 1504, 1280, 1280, 1536, 1568, 1600, 1632, 1664, 1696, 1728, 1727, 1760, 1727, 1792, 1824, 1856, 1888, 1920, 1952, 1984, 2016, 2048, 2080, 2112, 2144, 2176, 2208, 2240, 2272, 2304, 2336, 2368, 2400, 2432, 2464, 2496, 2528, 2560, 2592, 2624, 2656, 2688, 2720, 2752, 2784, 2816, 2720, 2848, 2880, 2912, 2944, 2976, 3008, 3040, 3072, 3104, 3136, 1727, 3168, 3200, 3232, 1727, 3264, 3296, 3328, 3360, 3392, 3424, 3456, 1727, 1280, 3488, 3520, 3552, 3584, 893, 3616, 3648, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 3680, 1280, 3712, 3744, 3776, 1280, 3808, 1280, 3840, 3872, 3904, 1280, 1280, 3936, 3968, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 4000, 4032, 1280, 1280, 4064, 4096, 4128, 4160, 4192, 1280, 4224, 4256, 4288, 4320, 1280, 4352, 4384, 1280, 4416, 1280, 4448, 4480, 4512, 4544, 4576, 1280, 4608, 4640, 4672, 4704, 1280, 4736, 4768, 4800, 4832, 1727, 1727, 4864, 4896, 4928, 4960, 4992, 5024, 1280, 5056, 1280, 5088, 5120, 5152, 1727, 1727, 5184, 5216, 527, 5248, 5280, 5312, 597, 5260, 704, 5344, 224, 224, 224, 224, 5376, 224, 224, 224, 5408, 5440, 5472, 5504, 5536, 5568, 5600, 5632, 5664, 5696, 5728, 5760, 5792, 5824, 5856, 5888, 5920, 5952, 5984, 6016, 6048, 6080, 6112, 6144, 6176, 6164, 6164, 6164, 6164, 6164, 6164, 6164, 6208, 6240, 4670, 6272, 6304, 6336, 6368, 6400, 4670, 6432, 6464, 6496, 6528, 4670, 4670, 6560, 4670, 4670, 4670, 4670, 4670, 6592, 6093, 6624, 4670, 4670, 4670, 6656, 4670, 4670, 4670, 4670, 4670, 4670, 4670, 6688, 6720, 4670, 6752, 6784, 4670, 4670, 4670, 4670, 4670, 4670, 4670, 4670, 6164, 6164, 6164, 6164, 6816, 6164, 6848, 6880, 6164, 6164, 6164, 6164, 6164, 6164, 6164, 6164, 4670, 6912, 6944, 6976, 7008, 7040, 7072, 1727, 893, 7104, 7136, 7168, 224, 224, 224, 7200, 527, 7232, 1280, 7264, 7296, 7328, 7328, 704, 7360, 7392, 7424, 1727, 7456, 4670, 4670, 7488, 4670, 4670, 4670, 4670, 4670, 4670, 7520, 7552, 7584, 7616, 3336, 1280, 7648, 3968, 1280, 7680, 4427, 7712, 1280, 1280, 7744, 1200, 4670, 7776, 7808, 7840, 7872, 4670, 7840, 7904, 4670, 7808, 4670, 4670, 4670, 4670, 4670, 4670, 4670, 4670, 7936, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 7968, 4670, 4670, 7936, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 8000, 1727, 8032, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 8064, 4670, 8096, 8128, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 8160, 8192, 224, 8224, 8256, 1280, 1280, 8288, 8320, 8352, 224, 8384, 8416, 8448, 1727, 8480, 8512, 8544, 1280, 8576, 8608, 8640, 8672, 8704, 1568, 8736, 8768, 8800, 1824, 8832, 8864, 8896, 1280, 8928, 8960, 8992, 1280, 9024, 9056, 9088, 9120, 9152, 9184, 9216, 1727, 1727, 1280, 9248, 7936, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 9280, 9312, 9344, 9376, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 9408, 9376, 1727, 1727, 9440, 9376, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 9440, 9472, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 9504, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 9536, 1280, 1280, 9568, 1727, 9600, 9632, 9664, 1280, 1280, 9696, 9728, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 9760, 1744, 1280, 9792, 1280, 9824, 9856, 9888, 9920, 9952, 9984, 1280, 1280, 1280, 10016, 10048, 10080, 10112, 10144, 5146, 4480, 10176, 10208, 10240, 10272, 10304, 1727, 1280, 1280, 1280, 1200, 10336, 10368, 6016, 10400, 10432, 10464, 10496, 10528, 1727, 1727, 1727, 1727, 8800, 1280, 10560, 10592, 1280, 10624, 10656, 10688, 10720, 1280, 10752, 1727, 893, 10784, 10816, 1280, 4560, 10848, 1727, 1727, 1280, 10880, 1280, 10912, 1727, 1727, 1727, 1727, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 7296, 9810, 10944, 1727, 1727, 1727, 1727, 10976, 11008, 11040, 11072, 4480, 11104, 1727, 1727, 11136, 11168, 1727, 1727, 1280, 11200, 1727, 1727, 11232, 11264, 11296, 11328, 11360, 1727, 11392, 11424, 1280, 11456, 11488, 11520, 11552, 11584, 1727, 1727, 1280, 1280, 11616, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 11648, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 11680, 11712, 11744, 11776, 4992, 11808, 11840, 11872, 11904, 11936, 11968, 12000, 4992, 12032, 12064, 12096, 12128, 12160, 1727, 1727, 1727, 1744, 12192, 12224, 2336, 12256, 12288, 12320, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1280, 12352, 12384, 1727, 1727, 1727, 1727, 1727, 1280, 12416, 12448, 1727, 1280, 12480, 12512, 1727, 1280, 12544, 10848, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 893, 527, 12576, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1280, 11856, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 11856, 1727, 1727, 1727, 6016, 6016, 6016, 12608, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 12640, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 11856, 4480, 12672, 1727, 1727, 1744, 12704, 1280, 12736, 12768, 12800, 12832, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1280, 1280, 12864, 12896, 12928, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 12960, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1280, 1280, 1280, 12992, 13024, 13056, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 4670, 4670, 4670, 4670, 4670, 4670, 4670, 7520, 4670, 6989, 4670, 13088, 13120, 13152, 13184, 1727, 4670, 4670, 13216, 1727, 1727, 1727, 1727, 1727, 4670, 4670, 8080, 13248, 1727, 1727, 1727, 1727, 13280, 13312, 13344, 13324, 13376, 13408, 13440, 13472, 13504, 13536, 13568, 13600, 13632, 13280, 13664, 13696, 13324, 13304, 13728, 13760, 13792, 13824, 13856, 13888, 13920, 13952, 13984, 14016, 14048, 14080, 14112, 14144, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1280, 1280, 1280, 1280, 1280, 1280, 14176, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 14208, 14240, 14272, 14304, 14336, 14368, 1727, 14400, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 4670, 14432, 4670, 4670, 14464, 14496, 14528, 7520, 14560, 14592, 4670, 14432, 14624, 1727, 1727, 14656, 14688, 14720, 14752, 1727, 1727, 1727, 1727, 1727, 4670, 14784, 4670, 14816, 4670, 4670, 14848, 14880, 4670, 4670, 4670, 4670, 4670, 4670, 4670, 7808, 4670, 4670, 14912, 7456, 4670, 14944, 4670, 4670, 4670, 4670, 6993, 4670, 4670, 4670, 14976, 15008, 4670, 4670, 4670, 15040, 4670, 4670, 14630, 1727, 14432, 4670, 15072, 4670, 15104, 15136, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 7936, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 7990, 1727, 7936, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 15168, 7936, 1727, 1727, 1727, 1727, 1727, 15200, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 4560, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 15232, 15264, 15264, 15264, 1727, 1727, 1727, 1727, 704, 704, 704, 704, 704, 704, 704, 15296, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 9472, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 15328, 9472, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 15360, }; const size_t* GeneralCategoryIndexPtr = GeneralCategoryIndex; const uint32_t GeneralCategoryData[15392] = { 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0x400000, 0x20000, 0x20000, 0x20000, 0x80000, 0x20000, 0x20000, 0x20000, 0x2000, 0x4000, 0x20000, 0x40000, 0x20000, 0x1000, 0x20000, 0x20000, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x20000, 0x20000, 0x40000, 0x40000, 0x40000, 0x20000, 0x20000, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x2000, 0x20000, 0x4000, 0x100000, 0x800, 0x100000, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x2000, 0x40000, 0x4000, 0x40000, 0x2000000, 0x400000, 0x20000, 0x80000, 0x80000, 0x80000, 0x80000, 0x200000, 0x20000, 0x100000, 0x200000, 0x10, 0x8000, 0x40000, 0x4000000, 0x200000, 0x100000, 0x200000, 0x40000, 0x400, 0x400, 0x100000, 0x02, 0x20000, 0x20000, 0x100000, 0x400, 0x10, 0x10000, 0x400, 0x400, 0x400, 0x20000, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40000, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x40000, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x02, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x01, 0x01, 0x02, 0x02, 0x10, 0x01, 0x02, 0x02, 0x02, 0x10, 0x10, 0x10, 0x10, 0x01, 0x04, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x04, 0x02, 0x01, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x02, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x10, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x100000, 0x100000, 0x100000, 0x100000, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x08, 0x08, 0x08, 0x08, 0x08, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x08, 0x100000, 0x08, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x02, 0x01, 0x02, 0x08, 0x100000, 0x01, 0x02, 0x00, 0x00, 0x08, 0x02, 0x02, 0x02, 0x20000, 0x01, 0x00, 0x00, 0x00, 0x00, 0x100000, 0x100000, 0x01, 0x20000, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x40000, 0x01, 0x02, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x200000, 0x20, 0x20, 0x20, 0x20, 0x20, 0x80, 0x80, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x08, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x20000, 0x1000, 0x00, 0x00, 0x200000, 0x200000, 0x80000, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1000, 0x20, 0x20000, 0x20, 0x20, 0x20000, 0x20, 0x20, 0x20000, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x20000, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x40000, 0x40000, 0x40000, 0x20000, 0x20000, 0x80000, 0x20000, 0x20000, 0x200000, 0x200000, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20000, 0x4000000, 0x00, 0x20000, 0x20000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x20000, 0x20000, 0x20000, 0x20000, 0x10, 0x10, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20000, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4000000, 0x200000, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x08, 0x08, 0x20, 0x20, 0x200000, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x10, 0x10, 0x10, 0x200000, 0x200000, 0x10, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x00, 0x4000000, 0x10, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x08, 0x08, 0x200000, 0x20000, 0x20000, 0x20000, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x08, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x08, 0x20, 0x20, 0x20, 0x08, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x00, 0x00, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x40, 0x20, 0x10, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x40, 0x40, 0x20, 0x40, 0x40, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20000, 0x20000, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x20000, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x40, 0x40, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x20, 0x10, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x40, 0x40, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x20, 0x20, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x10, 0x10, 0x80000, 0x80000, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x200000, 0x80000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x40, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x00, 0x20, 0x00, 0x40, 0x40, 0x40, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x20, 0x20, 0x10, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x40, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x20, 0x10, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x20, 0x20, 0x40, 0x00, 0x40, 0x40, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x20, 0x20, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x20000, 0x80000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40, 0x40, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x20, 0x10, 0x40, 0x20, 0x40, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x40, 0x40, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x20, 0x20, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x200000, 0x10, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x20, 0x40, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x00, 0x40, 0x40, 0x40, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x400, 0x400, 0x400, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x80000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40, 0x40, 0x40, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x10, 0x20, 0x20, 0x20, 0x40, 0x40, 0x40, 0x40, 0x00, 0x20, 0x20, 0x20, 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x20, 0x20, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x200000, 0x00, 0x20, 0x40, 0x40, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x20, 0x10, 0x40, 0x20, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x20, 0x40, 0x40, 0x00, 0x40, 0x40, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x10, 0x20, 0x20, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x00, 0x40, 0x40, 0x40, 0x00, 0x40, 0x40, 0x40, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x20, 0x20, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x00, 0x00, 0x00, 0x200000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x40, 0x40, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x00, 0x20, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x00, 0x00, 0x40, 0x40, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x80000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20000, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x20000, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x20, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x20, 0x20, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x08, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x200000, 0x200000, 0x200000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x200000, 0x20000, 0x200000, 0x200000, 0x200000, 0x20, 0x20, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x200000, 0x20, 0x200000, 0x20, 0x200000, 0x20, 0x2000, 0x4000, 0x2000, 0x4000, 0x40, 0x40, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20000, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x20, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x200000, 0x200000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x200000, 0x200000, 0x200000, 0x200000, 0x20000, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x20, 0x20, 0x40, 0x40, 0x20, 0x20, 0x10, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x40, 0x40, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x10, 0x40, 0x40, 0x40, 0x10, 0x10, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x40, 0x40, 0x20, 0x20, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x20, 0x10, 0x40, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x40, 0x40, 0x40, 0x20, 0x200000, 0x200000, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20000, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20000, 0x20000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x400000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x2000, 0x4000, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20000, 0x20000, 0x20000, 0x200, 0x200, 0x200, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20000, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x20, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20000, 0x20000, 0x20000, 0x08, 0x20000, 0x20000, 0x20000, 0x80000, 0x10, 0x20, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x1000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20, 0x20, 0x20, 0x4000000, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x20, 0x20, 0x20, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x20, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x00, 0x00, 0x00, 0x20000, 0x20000, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x400, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x20, 0x00, 0x00, 0x20000, 0x20000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x40, 0x20, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x20, 0x40, 0x20, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x20, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x08, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x80, 0x00, 0x20, 0x20, 0x20, 0x20, 0x40, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x20, 0x40, 0x40, 0x40, 0x40, 0x40, 0x20, 0x40, 0x40, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x20, 0x20, 0x40, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x40, 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x20, 0x20, 0x40, 0x20, 0x20, 0x20, 0x10, 0x10, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x40, 0x20, 0x20, 0x40, 0x40, 0x40, 0x20, 0x40, 0x20, 0x20, 0x20, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20000, 0x20000, 0x20000, 0x20000, 0x10, 0x10, 0x10, 0x10, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x20, 0x20, 0x00, 0x00, 0x00, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20000, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x20, 0x10, 0x10, 0x10, 0x10, 0x40, 0x40, 0x20, 0x10, 0x10, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x08, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x04, 0x100000, 0x02, 0x100000, 0x100000, 0x100000, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x04, 0x100000, 0x100000, 0x100000, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x00, 0x100000, 0x100000, 0x100000, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x100000, 0x100000, 0x100000, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x04, 0x100000, 0x100000, 0x00, 0x400000, 0x400000, 0x400000, 0x400000, 0x400000, 0x400000, 0x400000, 0x400000, 0x400000, 0x400000, 0x400000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x20000, 0x20000, 0x8000, 0x10000, 0x2000, 0x8000, 0x8000, 0x10000, 0x2000, 0x8000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x800000, 0x1000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x400000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x8000, 0x10000, 0x20000, 0x20000, 0x20000, 0x20000, 0x800, 0x800, 0x20000, 0x20000, 0x20000, 0x40000, 0x2000, 0x4000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x40000, 0x20000, 0x800, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x400000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x00, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x400, 0x08, 0x00, 0x00, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x40000, 0x40000, 0x40000, 0x2000, 0x4000, 0x08, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x40000, 0x40000, 0x40000, 0x2000, 0x4000, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x80000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x80, 0x80, 0x80, 0x80, 0x20, 0x80, 0x80, 0x80, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x01, 0x200000, 0x200000, 0x200000, 0x200000, 0x01, 0x200000, 0x200000, 0x02, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x01, 0x02, 0x200000, 0x01, 0x200000, 0x200000, 0x40000, 0x01, 0x01, 0x01, 0x01, 0x01, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x01, 0x200000, 0x01, 0x200000, 0x01, 0x200000, 0x01, 0x01, 0x01, 0x01, 0x200000, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x10, 0x10, 0x10, 0x10, 0x02, 0x200000, 0x200000, 0x02, 0x02, 0x01, 0x01, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x01, 0x02, 0x02, 0x02, 0x02, 0x200000, 0x40000, 0x200000, 0x200000, 0x02, 0x200000, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x01, 0x02, 0x200, 0x200, 0x200, 0x200, 0x400, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x40000, 0x40000, 0x200000, 0x200000, 0x200000, 0x200000, 0x40000, 0x200000, 0x200000, 0x40000, 0x200000, 0x200000, 0x40000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x40000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x40000, 0x40000, 0x200000, 0x200000, 0x40000, 0x200000, 0x40000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x2000, 0x4000, 0x2000, 0x4000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x40000, 0x40000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x2000, 0x4000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x40000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x40000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x40000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x2000, 0x4000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x2000, 0x4000, 0x2000, 0x4000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x2000, 0x4000, 0x40000, 0x40000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x200000, 0x200000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x08, 0x08, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x01, 0x02, 0x01, 0x02, 0x20, 0x20, 0x20, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20000, 0x20000, 0x20000, 0x20000, 0x400, 0x20000, 0x20000, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x20000, 0x20000, 0x8000, 0x10000, 0x8000, 0x10000, 0x20000, 0x20000, 0x20000, 0x8000, 0x10000, 0x20000, 0x8000, 0x10000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x1000, 0x20000, 0x20000, 0x1000, 0x20000, 0x8000, 0x10000, 0x20000, 0x20000, 0x8000, 0x10000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x08, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x1000, 0x1000, 0x20000, 0x20000, 0x20000, 0x20000, 0x1000, 0x20000, 0x2000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x400000, 0x20000, 0x20000, 0x20000, 0x200000, 0x08, 0x10, 0x200, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x200000, 0x200000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x1000, 0x2000, 0x4000, 0x4000, 0x200000, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x1000, 0x08, 0x08, 0x08, 0x08, 0x08, 0x200000, 0x200000, 0x200, 0x200, 0x200, 0x08, 0x10, 0x20000, 0x200000, 0x200000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x20, 0x20, 0x100000, 0x100000, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20000, 0x08, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x200000, 0x200000, 0x400, 0x400, 0x400, 0x400, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x200000, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x20000, 0x20000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x20000, 0x20000, 0x20000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x10, 0x20, 0x80, 0x80, 0x80, 0x20000, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20000, 0x08, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x08, 0x08, 0x00, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x20, 0x20, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x100000, 0x100000, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x02, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x08, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x08, 0x100000, 0x100000, 0x01, 0x02, 0x01, 0x02, 0x00, 0x01, 0x02, 0x01, 0x02, 0x02, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x08, 0x02, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x10, 0x10, 0x10, 0x20, 0x10, 0x10, 0x10, 0x10, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x40, 0x40, 0x20, 0x20, 0x40, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x200000, 0x200000, 0x80000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20000, 0x20000, 0x20000, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20000, 0x20000, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20000, 0x20000, 0x20000, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20000, 0x20000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x20, 0x40, 0x40, 0x40, 0x40, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x00, 0x08, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x00, 0x00, 0x00, 0x00, 0x20000, 0x20000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x20, 0x20, 0x40, 0x40, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x40, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x00, 0x00, 0x20000, 0x20000, 0x20000, 0x20000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x200000, 0x200000, 0x200000, 0x10, 0x40, 0x20, 0x40, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x10, 0x20, 0x20, 0x20, 0x10, 0x10, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x10, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x08, 0x20000, 0x20000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x40, 0x20, 0x20, 0x40, 0x40, 0x20000, 0x20000, 0x10, 0x08, 0x08, 0x40, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x100000, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x40, 0x40, 0x20, 0x40, 0x40, 0x20, 0x40, 0x40, 0x20000, 0x40, 0x20, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x8000000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8000000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8000000, 0x10000000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10000000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x40000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x4000, 0x2000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x80000, 0x200000, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x2000, 0x4000, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x20000, 0x1000, 0x1000, 0x800, 0x800, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x20000, 0x20000, 0x2000, 0x4000, 0x20000, 0x20000, 0x20000, 0x20000, 0x800, 0x800, 0x800, 0x20000, 0x20000, 0x20000, 0x00, 0x20000, 0x20000, 0x20000, 0x20000, 0x1000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x4000, 0x20000, 0x20000, 0x20000, 0x40000, 0x1000, 0x40000, 0x40000, 0x40000, 0x00, 0x20000, 0x80000, 0x20000, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x4000000, 0x00, 0x20000, 0x20000, 0x20000, 0x80000, 0x20000, 0x20000, 0x20000, 0x2000, 0x4000, 0x20000, 0x40000, 0x20000, 0x1000, 0x20000, 0x20000, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x20000, 0x20000, 0x40000, 0x40000, 0x40000, 0x20000, 0x20000, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x2000, 0x20000, 0x4000, 0x100000, 0x800, 0x100000, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x2000, 0x40000, 0x4000, 0x40000, 0x2000, 0x4000, 0x20000, 0x2000, 0x4000, 0x20000, 0x20000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x80000, 0x80000, 0x40000, 0x100000, 0x200000, 0x80000, 0x80000, 0x00, 0x200000, 0x40000, 0x40000, 0x40000, 0x40000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4000000, 0x4000000, 0x4000000, 0x200000, 0x200000, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x20000, 0x20000, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x400, 0x400, 0x400, 0x400, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x400, 0x400, 0x200000, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x20, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x00, 0x00, 0x00, 0x00, 0x400, 0x400, 0x400, 0x400, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x200, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x200, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x20000, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20000, 0x200, 0x200, 0x200, 0x200, 0x200, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x20000, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x200000, 0x200000, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x00, 0x00, 0x00, 0x20000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x400, 0x400, 0x20000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x400, 0x400, 0x400, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x200000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x400, 0x400, 0x400, 0x400, 0x400, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20000, 0x20000, 0x20000, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x00, 0x40, 0x20, 0x40, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x20, 0x20, 0x20000, 0x20000, 0x4000000, 0x20000, 0x20000, 0x20000, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x20000, 0x20000, 0x20000, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20000, 0x20000, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x10, 0x10, 0x10, 0x10, 0x20000, 0x20000, 0x20000, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x20000, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x40, 0x40, 0x20, 0x40, 0x20, 0x20, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x20, 0x10, 0x40, 0x40, 0x20, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x40, 0x40, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x20, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x40, 0x20, 0x20, 0x10, 0x10, 0x20000, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x40, 0x20, 0x20, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x20, 0x40, 0x20, 0x20, 0x20000, 0x20000, 0x20000, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x40, 0x20, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x00, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x00, 0x00, 0x00, 0x00, 0x20000, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x200000, 0x200000, 0x200000, 0x200000, 0x08, 0x08, 0x08, 0x08, 0x20000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x00, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x200000, 0x20, 0x20, 0x20000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x40, 0x40, 0x20, 0x20, 0x20, 0x200000, 0x200000, 0x200000, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x200000, 0x200000, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x20, 0x20, 0x20, 0x20, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x200000, 0x200000, 0x20, 0x20, 0x20, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40000, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x40000, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40000, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x40000, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40000, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x40000, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40000, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x40000, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40000, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x40000, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x00, 0x00, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40000, 0x40000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x200000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x4000000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x4000000, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10000000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10000000, 0x00, 0x00, }; const uint32_t* GeneralCategoryDataPtr = GeneralCategoryData; const size_t CanonicalCombiningClassIndex[34816] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 64, 96, 128, 0, 0, 0, 0, 0, 0, 0, 0, 160, 0, 0, 0, 0, 0, 0, 0, 192, 224, 256, 0, 288, 0, 320, 352, 0, 0, 384, 416, 448, 480, 512, 0, 0, 0, 0, 544, 576, 608, 640, 0, 0, 0, 0, 672, 0, 704, 736, 0, 0, 704, 768, 0, 0, 704, 800, 0, 0, 704, 832, 0, 0, 704, 864, 0, 0, 0, 896, 0, 0, 0, 928, 0, 0, 704, 960, 0, 0, 0, 992, 0, 0, 0, 1024, 0, 0, 1056, 1088, 0, 0, 1120, 1152, 0, 1184, 1216, 0, 1248, 1280, 0, 1312, 0, 0, 1344, 0, 0, 1376, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1408, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1440, 1440, 0, 0, 0, 0, 1472, 0, 0, 0, 0, 0, 0, 1504, 0, 0, 0, 1536, 0, 0, 0, 0, 0, 0, 1568, 0, 0, 1600, 0, 1632, 0, 0, 0, 1664, 777, 1696, 0, 1728, 0, 1760, 0, 1792, 0, 0, 0, 0, 1824, 1856, 0, 0, 0, 0, 0, 0, 1888, 1920, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1952, 1984, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1422, 0, 0, 0, 782, 0, 0, 0, 1905, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2016, 0, 0, 2048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2080, 2112, 0, 0, 2144, 0, 0, 0, 0, 0, 0, 0, 0, 1454, 0, 0, 0, 0, 0, 777, 2176, 0, 2208, 2240, 0, 0, 2272, 781, 0, 0, 0, 0, 0, 0, 2304, 2336, 951, 0, 0, 0, 0, 0, 0, 0, 2368, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2432, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2464, 0, 0, 0, 0, 0, 0, 0, 429, 0, 0, 0, 2496, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2528, 2560, 0, 0, 0, 0, 0, 2592, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1454, 782, 0, 2624, 0, 0, 2656, 2688, 0, 2720, 0, 0, 781, 0, 0, 2752, 0, 0, 0, 0, 0, 2784, 0, 704, 2816, 2848, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2880, 0, 0, 0, 0, 0, 0, 782, 2739, 0, 0, 782, 0, 0, 0, 2912, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2944, 0, 2976, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3040, 3072, 3104, 0, 0, 0, 0, 2654, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const size_t* CanonicalCombiningClassIndexPtr = CanonicalCombiningClassIndex; const uint8_t CanonicalCombiningClassData[3168] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE8, 0xDC, 0xDC, 0xDC, 0xDC, 0xE8, 0xD8, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xCA, 0xCA, 0xDC, 0xDC, 0xDC, 0xDC, 0xCA, 0xCA, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0x01, 0x01, 0x01, 0x01, 0x01, 0xDC, 0xDC, 0xDC, 0xDC, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xF0, 0xE6, 0xDC, 0xDC, 0xDC, 0xE6, 0xE6, 0xE6, 0xDC, 0xDC, 0x00, 0xE6, 0xE6, 0xE6, 0xDC, 0xDC, 0xDC, 0xDC, 0xE6, 0xE8, 0xDC, 0xDC, 0xE6, 0xE9, 0xEA, 0xEA, 0xE9, 0xEA, 0xEA, 0xE9, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xE6, 0xE6, 0xE6, 0xE6, 0xDC, 0xE6, 0xE6, 0xE6, 0xDE, 0xDC, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xE6, 0xE6, 0xDC, 0xE6, 0xE6, 0xDE, 0xE4, 0xE6, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x13, 0x14, 0x15, 0x16, 0x00, 0x17, 0x00, 0x18, 0x19, 0x00, 0xE6, 0xDC, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0x1E, 0x1F, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0xE6, 0xE6, 0xDC, 0xDC, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xDC, 0xE6, 0xE6, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0x00, 0x00, 0xE6, 0xE6, 0xE6, 0xE6, 0xDC, 0xE6, 0x00, 0x00, 0xE6, 0xE6, 0x00, 0xDC, 0xE6, 0xE6, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xDC, 0xE6, 0xE6, 0xDC, 0xE6, 0xE6, 0xDC, 0xDC, 0xDC, 0xE6, 0xDC, 0xDC, 0xE6, 0xDC, 0xE6, 0xE6, 0xE6, 0xDC, 0xE6, 0xDC, 0xE6, 0xDC, 0xE6, 0xDC, 0xE6, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xDC, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0xE6, 0xE6, 0x00, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0x00, 0xE6, 0xE6, 0xE6, 0x00, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0xDC, 0xE6, 0xE6, 0xDC, 0xE6, 0xE6, 0xE6, 0xDC, 0xDC, 0xDC, 0x1B, 0x1C, 0x1D, 0xE6, 0xE6, 0xE6, 0xDC, 0xE6, 0xE6, 0xDC, 0xDC, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xE6, 0xDC, 0xE6, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x5B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x67, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6B, 0x6B, 0x6B, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7A, 0x7A, 0x7A, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x00, 0xDC, 0x00, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x82, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x82, 0x82, 0x82, 0x00, 0x00, 0x82, 0x00, 0xE6, 0xE6, 0x09, 0x00, 0xE6, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x09, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xE6, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xE6, 0xE6, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xDC, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0xE6, 0x00, 0x01, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xE6, 0xE6, 0xDC, 0xDC, 0xDC, 0xDC, 0xE6, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0xDC, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xDC, 0xE6, 0xE6, 0xEA, 0xD6, 0xDC, 0xCA, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0xDC, 0xE6, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0x01, 0x01, 0xE6, 0xE6, 0xE6, 0xE6, 0x01, 0x01, 0x01, 0xE6, 0xE6, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x00, 0x00, 0x00, 0x01, 0x01, 0xE6, 0xDC, 0xE6, 0x01, 0x01, 0xDC, 0xDC, 0xDC, 0xDC, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xE4, 0xE8, 0xDE, 0xE0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x00, 0xE6, 0xE6, 0xDC, 0x00, 0x00, 0xE6, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0x00, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x00, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x00, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x01, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xD8, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0xE2, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0x00, 0x00, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xDC, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0xE6, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t* CanonicalCombiningClassDataPtr = CanonicalCombiningClassData; const size_t QuickCheckCaseMappedIndex[34816] = { 0, 0, 32, 64, 0, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 192, 448, 480, 512, 544, 0, 0, 0, 0, 0, 576, 608, 640, 672, 704, 736, 768, 800, 832, 192, 864, 192, 896, 192, 192, 928, 960, 992, 1024, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 765, 1056, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1088, 0, 0, 0, 0, 192, 192, 192, 192, 1120, 192, 192, 192, 1152, 1184, 1216, 1248, 1280, 1312, 1344, 1376, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1408, 1440, 1472, 1504, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1536, 1472, 1568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 765, 1600, 1632, 1664, 192, 192, 192, 1696, 816, 1728, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 1760, 1792, 0, 0, 0, 0, 1824, 192, 1856, 1888, 1920, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1952, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 1984, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 765, 2016, 2048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 765, 816, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const size_t* QuickCheckCaseMappedIndexPtr = QuickCheckCaseMappedIndex; const uint8_t QuickCheckCaseMappedData[2080] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0D, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x00, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0D, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0D, 0x05, 0x0A, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x0A, 0x05, 0x0A, 0x0A, 0x0A, 0x05, 0x00, 0x0A, 0x0A, 0x0A, 0x0A, 0x05, 0x0A, 0x0A, 0x05, 0x0A, 0x0A, 0x0A, 0x05, 0x05, 0x00, 0x0A, 0x0A, 0x05, 0x0A, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x0A, 0x05, 0x0A, 0x00, 0x00, 0x0A, 0x05, 0x0A, 0x0A, 0x05, 0x0A, 0x0A, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x0A, 0x05, 0x00, 0x00, 0x0A, 0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x0B, 0x05, 0x0E, 0x0B, 0x05, 0x0E, 0x0B, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0D, 0x0E, 0x0B, 0x05, 0x0A, 0x05, 0x0A, 0x0A, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x00, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0A, 0x05, 0x0A, 0x0A, 0x05, 0x05, 0x0A, 0x05, 0x0A, 0x0A, 0x0A, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x05, 0x05, 0x00, 0x05, 0x00, 0x05, 0x05, 0x00, 0x00, 0x00, 0x05, 0x05, 0x00, 0x05, 0x00, 0x05, 0x05, 0x00, 0x05, 0x05, 0x00, 0x05, 0x05, 0x00, 0x00, 0x05, 0x00, 0x05, 0x05, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x05, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x05, 0x0A, 0x05, 0x00, 0x00, 0x0A, 0x05, 0x00, 0x00, 0x00, 0x05, 0x05, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x0A, 0x0A, 0x0A, 0x00, 0x0A, 0x00, 0x0A, 0x0A, 0x0D, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x0D, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0D, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0A, 0x0D, 0x0D, 0x00, 0x00, 0x00, 0x0D, 0x0D, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0D, 0x0D, 0x05, 0x05, 0x0A, 0x0D, 0x00, 0x0A, 0x05, 0x0A, 0x0A, 0x05, 0x00, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0A, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x00, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x00, 0x00, 0x0A, 0x00, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x00, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, 0x00, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x00, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, 0x00, 0x0D, 0x05, 0x0D, 0x05, 0x0D, 0x05, 0x0D, 0x05, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x00, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x05, 0x05, 0x0D, 0x0D, 0x0D, 0x00, 0x0D, 0x0D, 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0D, 0x0D, 0x0D, 0x00, 0x0D, 0x0D, 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x00, 0x00, 0x00, 0x05, 0x05, 0x0D, 0x0D, 0x00, 0x00, 0x0D, 0x0D, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, 0x0D, 0x0D, 0x0D, 0x05, 0x0D, 0x0D, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x0D, 0x0D, 0x00, 0x0D, 0x0D, 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x0A, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x0A, 0x05, 0x0A, 0x0A, 0x0A, 0x05, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, 0x0A, 0x05, 0x00, 0x0A, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0A, 0x0A, 0x05, 0x0A, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x05, 0x0A, 0x05, 0x00, 0x00, 0x00, 0x0A, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x00, 0x00, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x00, 0x00, 0x00, 0x0A, 0x05, 0x0A, 0x00, 0x00, 0x0A, 0x05, 0x0A, 0x05, 0x00, 0x00, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, 0x00, 0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t* QuickCheckCaseMappedDataPtr = QuickCheckCaseMappedData; const size_t QuickCheckNFCIndex[34816] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 64, 96, 128, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 256, 0, 0, 288, 320, 0, 0, 352, 384, 0, 0, 0, 0, 0, 0, 288, 416, 0, 0, 288, 448, 0, 0, 0, 480, 0, 0, 0, 512, 0, 0, 288, 544, 0, 0, 0, 576, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 608, 640, 672, 704, 0, 0, 0, 736, 0, 0, 0, 0, 0, 0, 0, 0, 0, 768, 0, 800, 211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 832, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 864, 0, 896, 928, 960, 286, 0, 0, 0, 0, 0, 0, 0, 0, 992, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1024, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1056, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1088, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1152, 1184, 1120, 1216, 1120, 1120, 1248, 0, 1280, 1312, 1344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1376, 0, 0, 0, 1408, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 288, 1440, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1472, 0, 0, 0, 0, 0, 0, 0, 1448, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1504, 1536, 0, 253, 167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const size_t* QuickCheckNFCIndexPtr = QuickCheckNFCIndex; const uint8_t QuickCheckNFCData[1600] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, }; const uint8_t* QuickCheckNFCDataPtr = QuickCheckNFCData; const size_t QuickCheckNFDIndex[34816] = { 0, 0, 0, 0, 0, 0, 32, 64, 96, 128, 160, 192, 0, 224, 256, 288, 320, 352, 0, 0, 0, 0, 0, 0, 0, 0, 384, 416, 448, 480, 512, 0, 544, 576, 608, 640, 0, 0, 672, 704, 0, 0, 0, 0, 0, 0, 0, 0, 0, 736, 0, 0, 0, 0, 768, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 800, 832, 0, 0, 0, 864, 0, 0, 896, 928, 0, 0, 0, 0, 0, 0, 0, 960, 0, 992, 0, 1024, 0, 0, 0, 1056, 0, 0, 0, 1088, 0, 0, 0, 1024, 0, 0, 0, 1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1152, 1184, 1216, 1248, 0, 0, 0, 1280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1312, 1344, 1376, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 312, 312, 312, 312, 1408, 312, 312, 1440, 1472, 312, 1504, 1536, 312, 1568, 1600, 1632, 1664, 0, 0, 0, 0, 0, 0, 0, 0, 1696, 0, 0, 1728, 1760, 1792, 0, 1824, 1856, 1888, 1920, 1952, 1984, 0, 2016, 0, 2048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2080, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2112, 2144, 2176, 2208, 2240, 2272, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 2304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 312, 312, 312, 312, 312, 312, 312, 312, 2336, 2368, 312, 2400, 312, 312, 1440, 0, 2432, 2464, 2496, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2528, 2560, 0, 0, 0, 2592, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2624, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2656, 0, 0, 0, 0, 0, 0, 0, 2688, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1775, 2720, 0, 2752, 820, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 2784, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const size_t* QuickCheckNFDIndexPtr = QuickCheckNFDIndex; const uint8_t QuickCheckNFDData[2816] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, }; const uint8_t* QuickCheckNFDDataPtr = QuickCheckNFDData; const size_t QuickCheckNFKCIndex[34816] = { 0, 0, 0, 0, 0, 32, 0, 0, 0, 64, 96, 128, 0, 0, 160, 192, 0, 0, 0, 0, 0, 224, 256, 288, 320, 352, 384, 416, 448, 0, 480, 512, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 544, 0, 0, 0, 0, 0, 576, 608, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 640, 672, 0, 0, 704, 736, 0, 0, 768, 800, 0, 0, 0, 0, 0, 0, 704, 832, 0, 0, 704, 864, 0, 0, 0, 896, 0, 0, 0, 928, 0, 0, 704, 960, 0, 0, 0, 992, 0, 0, 1024, 0, 0, 0, 1024, 1056, 0, 1088, 0, 1120, 1152, 1184, 1216, 0, 0, 0, 1248, 0, 0, 0, 0, 0, 1280, 0, 0, 0, 1312, 0, 1344, 595, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1376, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1408, 1440, 1472, 669, 1504, 0, 0, 0, 0, 0, 0, 1536, 0, 0, 0, 0, 0, 0, 1568, 0, 1600, 1632, 1664, 1696, 1728, 1760, 1792, 1824, 97, 0, 0, 1856, 1888, 1920, 1504, 1034, 0, 0, 0, 0, 1952, 0, 0, 0, 0, 0, 0, 0, 1984, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1504, 1504, 1504, 1504, 2016, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1229, 0, 0, 2048, 0, 0, 2080, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2112, 0, 0, 0, 0, 0, 0, 0, 2144, 0, 0, 0, 0, 0, 0, 0, 0, 249, 0, 0, 1024, 1504, 1504, 1504, 1504, 1504, 1504, 2176, 0, 105, 2208, 0, 0, 2240, 0, 0, 249, 0, 2272, 1504, 1504, 2304, 0, 0, 0, 2336, 1504, 2368, 2400, 1504, 1504, 1504, 2432, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2464, 0, 0, 0, 0, 0, 0, 2496, 0, 0, 0, 1969, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 2528, 2560, 1504, 2592, 1504, 1504, 2624, 0, 2656, 2688, 2720, 1504, 1504, 2752, 2784, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 2289, 2160, 1504, 2816, 1504, 696, 2848, 2880, 2160, 2912, 2944, 1504, 1504, 1504, 2976, 1503, 1504, 1504, 1504, 1504, 2432, 3008, 3040, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3072, 0, 0, 0, 3104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 704, 3136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3168, 0, 0, 0, 0, 0, 0, 0, 1008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3200, 288, 0, 669, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1504, 1504, 3232, 1504, 3264, 3296, 3328, 1504, 3360, 3392, 3424, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 3456, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 3488, 1504, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3520, 3552, 3584, 3616, 3648, 3680, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3712, 2416, 3744, 3776, 3808, 0, 0, 0, 3840, 3872, 3904, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 2289, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const size_t* QuickCheckNFKCIndexPtr = QuickCheckNFKCIndex; const uint8_t QuickCheckNFKCData[3936] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t* QuickCheckNFKCDataPtr = QuickCheckNFKCData; const size_t QuickCheckNFKDIndex[34816] = { 0, 0, 0, 0, 0, 32, 64, 96, 128, 160, 192, 224, 0, 256, 288, 320, 352, 384, 0, 0, 0, 416, 448, 480, 0, 0, 512, 544, 576, 608, 640, 672, 704, 736, 768, 800, 0, 0, 832, 864, 0, 0, 0, 0, 896, 0, 0, 0, 0, 478, 0, 928, 0, 0, 960, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 992, 1024, 0, 0, 0, 1056, 0, 0, 1088, 1120, 0, 0, 0, 0, 0, 0, 0, 1152, 0, 1184, 0, 1216, 0, 0, 0, 1248, 0, 0, 0, 1280, 0, 0, 0, 1216, 0, 0, 0, 1312, 0, 0, 1344, 0, 0, 0, 1376, 1408, 0, 1440, 0, 1472, 1504, 1536, 1568, 0, 0, 0, 897, 0, 0, 0, 0, 0, 1600, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1632, 1664, 1696, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1728, 1760, 1792, 1824, 344, 0, 0, 344, 344, 344, 344, 1775, 344, 344, 232, 1856, 344, 1888, 1920, 344, 1952, 1984, 2016, 2048, 2080, 2112, 2144, 2176, 2208, 0, 0, 2240, 2272, 2304, 344, 2336, 1438, 2368, 0, 2400, 2432, 2464, 2496, 2528, 2560, 0, 2592, 0, 2624, 0, 0, 0, 0, 0, 0, 0, 0, 0, 344, 344, 344, 344, 2656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1581, 0, 0, 2688, 0, 0, 2720, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2752, 0, 0, 0, 0, 0, 0, 0, 746, 0, 0, 0, 0, 0, 0, 0, 0, 441, 0, 0, 2784, 344, 344, 344, 344, 344, 344, 2816, 0, 440, 2848, 2880, 2912, 2944, 2976, 3008, 3040, 0, 3072, 344, 344, 3104, 0, 0, 0, 1919, 344, 3136, 1919, 344, 344, 344, 1919, 344, 344, 344, 344, 344, 344, 344, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3168, 0, 0, 0, 0, 0, 0, 963, 0, 0, 0, 3200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 404, 0, 0, 0, 0, 0, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 344, 344, 344, 344, 344, 344, 344, 344, 3232, 3264, 344, 3296, 344, 344, 232, 0, 3328, 3360, 3392, 344, 344, 3424, 273, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 3089, 3456, 344, 326, 344, 3434, 3488, 3520, 3552, 3584, 3616, 344, 344, 344, 3648, 3397, 344, 344, 344, 344, 1919, 3680, 3712, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3744, 2205, 0, 0, 0, 3776, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3808, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3840, 0, 0, 0, 0, 0, 0, 0, 3198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3442, 480, 0, 3872, 440, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 344, 344, 1952, 344, 3904, 3936, 3968, 344, 4000, 4032, 4064, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 4096, 344, 344, 344, 344, 344, 344, 344, 344, 4128, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4160, 4192, 4224, 4256, 4288, 4320, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4352, 4384, 3152, 4416, 963, 0, 0, 0, 4448, 4480, 4512, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 3089, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const size_t* QuickCheckNFKDIndexPtr = QuickCheckNFKDIndex; const uint8_t QuickCheckNFKDData[4544] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t* QuickCheckNFKDDataPtr = QuickCheckNFKDData; const uint32_t NFDIndex1[272] = { 0, 128, 256, 384, 512, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 640, 392, 768, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 896, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 1024, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, }; const uint32_t* NFDIndex1Ptr = NFDIndex1; const uint32_t NFDIndex2[1152] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0x0, 0xE0, 0x100, 0x120, 0x140, 0x160, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x180, 0x1A0, 0x1C0, 0x1E0, 0x200, 0x0, 0x220, 0x240, 0x260, 0x280, 0x0, 0x0, 0x2A0, 0x2C0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2E0, 0x0, 0x0, 0x0, 0x0, 0x300, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x320, 0x340, 0x0, 0x0, 0x0, 0x360, 0x0, 0x0, 0x380, 0x3A0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3C0, 0x0, 0x3E0, 0x0, 0x400, 0x0, 0x0, 0x0, 0x420, 0x0, 0x0, 0x0, 0x440, 0x0, 0x0, 0x0, 0x460, 0x0, 0x0, 0x0, 0x480, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4A0, 0x4C0, 0x4E0, 0x500, 0x0, 0x0, 0x0, 0x520, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x540, 0x560, 0x580, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5A0, 0x5C0, 0x5E0, 0x600, 0x620, 0x640, 0x660, 0x680, 0x6A0, 0x6C0, 0x6E0, 0x700, 0x720, 0x740, 0x760, 0x780, 0x7A0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7C0, 0x0, 0x0, 0x7E0, 0x800, 0x820, 0x0, 0x840, 0x860, 0x880, 0x8A0, 0x8C0, 0x8E0, 0x0, 0x900, 0x0, 0x920, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x940, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x960, 0x980, 0x9A0, 0x9C0, 0x9E0, 0xA00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xA20, 0xA40, 0xA60, 0xA80, 0xAA0, 0xAC0, 0xAE0, 0xB00, 0xB20, 0xB40, 0xB60, 0xB80, 0xBA0, 0xBC0, 0xBE0, 0x0, 0xC00, 0xC20, 0xC40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xC60, 0xC80, 0x0, 0x0, 0x0, 0xCA0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xCC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xCE0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xD00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xD20, 0xD40, 0x0, 0xD60, 0xD80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xDA0, 0xDC0, 0xDE0, 0xE00, 0xE20, 0xE40, 0xE60, 0xE80, 0xEA0, 0xEC0, 0xEE0, 0xF00, 0xF20, 0xF40, 0xF60, 0xF80, 0xFA0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, }; const uint32_t* NFDIndex2Ptr = NFDIndex2; const uint32_t NFDData[4032] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3000000, 0x3000003, 0x3000006, 0x3000009, 0x300000C, 0x300000F, 0x0, 0x3000012, 0x3000015, 0x3000018, 0x300001B, 0x300001E, 0x3000021, 0x3000024, 0x3000027, 0x300002A, 0x0, 0x300002D, 0x3000030, 0x3000033, 0x3000036, 0x3000039, 0x300003C, 0x0, 0x0, 0x300003F, 0x3000042, 0x3000045, 0x3000048, 0x300004B, 0x0, 0x0, 0x300004E, 0x3000051, 0x3000054, 0x3000057, 0x300005A, 0x300005D, 0x0, 0x3000060, 0x3000063, 0x3000066, 0x3000069, 0x300006C, 0x300006F, 0x3000072, 0x3000075, 0x3000078, 0x0, 0x300007B, 0x300007E, 0x3000081, 0x3000084, 0x3000087, 0x300008A, 0x0, 0x0, 0x300008D, 0x3000090, 0x3000093, 0x3000096, 0x3000099, 0x0, 0x300009C, 0x300009F, 0x30000A2, 0x30000A5, 0x30000A8, 0x30000AB, 0x30000AE, 0x30000B1, 0x30000B4, 0x30000B7, 0x30000BA, 0x30000BD, 0x30000C0, 0x30000C3, 0x30000C6, 0x30000C9, 0x30000CC, 0x0, 0x0, 0x30000CF, 0x30000D2, 0x30000D5, 0x30000D8, 0x30000DB, 0x30000DE, 0x30000E1, 0x30000E4, 0x30000E7, 0x30000EA, 0x30000ED, 0x30000F0, 0x30000F3, 0x30000F6, 0x30000F9, 0x30000FC, 0x30000FF, 0x3000102, 0x3000105, 0x3000108, 0x0, 0x0, 0x300010B, 0x300010E, 0x3000111, 0x3000114, 0x3000117, 0x300011A, 0x300011D, 0x3000120, 0x3000123, 0x0, 0x0, 0x0, 0x3000126, 0x3000129, 0x300012C, 0x300012F, 0x0, 0x3000132, 0x3000135, 0x3000138, 0x300013B, 0x300013E, 0x3000141, 0x0, 0x0, 0x0, 0x0, 0x3000144, 0x3000147, 0x300014A, 0x300014D, 0x3000150, 0x3000153, 0x0, 0x0, 0x0, 0x3000156, 0x3000159, 0x300015C, 0x300015F, 0x3000162, 0x3000165, 0x0, 0x0, 0x3000168, 0x300016B, 0x300016E, 0x3000171, 0x3000174, 0x3000177, 0x300017A, 0x300017D, 0x3000180, 0x3000183, 0x3000186, 0x3000189, 0x300018C, 0x300018F, 0x3000192, 0x3000195, 0x3000198, 0x300019B, 0x0, 0x0, 0x300019E, 0x30001A1, 0x30001A4, 0x30001A7, 0x30001AA, 0x30001AD, 0x30001B0, 0x30001B3, 0x30001B6, 0x30001B9, 0x30001BC, 0x30001BF, 0x30001C2, 0x30001C5, 0x30001C8, 0x30001CB, 0x30001CE, 0x30001D1, 0x30001D4, 0x30001D7, 0x30001DA, 0x30001DD, 0x30001E0, 0x0, 0x30001E3, 0x30001E6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30001E9, 0x30001EC, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30001EF, 0x30001F2, 0x30001F5, 0x30001F8, 0x30001FB, 0x30001FE, 0x3000201, 0x3000204, 0x5000207, 0x500020C, 0x5000211, 0x5000216, 0x500021B, 0x5000220, 0x5000225, 0x500022A, 0x0, 0x500022F, 0x5000234, 0x5000239, 0x500023E, 0x4000243, 0x4000247, 0x0, 0x0, 0x300024B, 0x300024E, 0x3000251, 0x3000254, 0x3000257, 0x300025A, 0x500025D, 0x5000262, 0x4000267, 0x400026B, 0x300026F, 0x0, 0x0, 0x0, 0x3000272, 0x3000275, 0x0, 0x0, 0x3000278, 0x300027B, 0x500027E, 0x5000283, 0x4000288, 0x400028C, 0x4000290, 0x4000294, 0x3000298, 0x300029B, 0x300029E, 0x30002A1, 0x30002A4, 0x30002A7, 0x30002AA, 0x30002AD, 0x30002B0, 0x30002B3, 0x30002B6, 0x30002B9, 0x30002BC, 0x30002BF, 0x30002C2, 0x30002C5, 0x30002C8, 0x30002CB, 0x30002CE, 0x30002D1, 0x30002D4, 0x30002D7, 0x30002DA, 0x30002DD, 0x30002E0, 0x30002E3, 0x30002E6, 0x30002E9, 0x0, 0x0, 0x30002EC, 0x30002EF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3000239, 0x300023E, 0x30002F2, 0x30002F5, 0x50002F8, 0x50002FD, 0x5000302, 0x5000307, 0x300030C, 0x300030F, 0x5000312, 0x5000317, 0x300031C, 0x300031F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000001, 0x2000004, 0x0, 0x2000322, 0x4000212, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000324, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000326, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000327, 0x400032B, 0x200032F, 0x4000331, 0x4000335, 0x4000339, 0x0, 0x400033D, 0x0, 0x4000341, 0x4000345, 0x6000349, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x400034F, 0x4000353, 0x4000357, 0x400035B, 0x400035F, 0x4000363, 0x6000367, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000349, 0x4000367, 0x400036D, 0x4000371, 0x4000375, 0x0, 0x0, 0x0, 0x0, 0x4000379, 0x400037D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000381, 0x4000385, 0x0, 0x4000389, 0x0, 0x0, 0x0, 0x400038D, 0x0, 0x0, 0x0, 0x0, 0x4000391, 0x4000395, 0x4000399, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x400039D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40003A1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40003A5, 0x40003A9, 0x0, 0x40003AD, 0x0, 0x0, 0x0, 0x40003B1, 0x0, 0x0, 0x0, 0x0, 0x40003B5, 0x40003B9, 0x40003BD, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40003C1, 0x40003C5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40003C9, 0x40003CD, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40003D1, 0x40003D5, 0x40003D9, 0x40003DD, 0x0, 0x0, 0x40003E1, 0x40003E5, 0x0, 0x0, 0x40003E9, 0x40003ED, 0x40003F1, 0x40003F5, 0x40003F9, 0x40003FD, 0x0, 0x0, 0x4000401, 0x4000405, 0x4000409, 0x400040D, 0x4000411, 0x4000415, 0x0, 0x0, 0x4000419, 0x400041D, 0x4000421, 0x4000425, 0x4000429, 0x400042D, 0x4000431, 0x4000435, 0x4000439, 0x400043D, 0x4000441, 0x4000445, 0x0, 0x0, 0x4000449, 0x400044D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000451, 0x4000455, 0x4000459, 0x400045D, 0x4000461, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000465, 0x0, 0x4000469, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x400046D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000471, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000477, 0x0, 0x0, 0x600047D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000483, 0x6000489, 0x600048F, 0x6000495, 0x600049B, 0x60004A1, 0x60004A7, 0x60004AD, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60004B3, 0x60004B9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60004BF, 0x60004C5, 0x0, 0x60004CB, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60004D1, 0x0, 0x0, 0x60004D7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60004DD, 0x60004E3, 0x60004E9, 0x0, 0x0, 0x60004EF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60004F5, 0x0, 0x0, 0x60004FB, 0x6000501, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000507, 0x600050D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000513, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000519, 0x600051F, 0x6000525, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x600052B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000531, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000537, 0x600053D, 0x0, 0x6000543, 0x9000549, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000552, 0x6000558, 0x600055E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000564, 0x0, 0x600056A, 0x9000570, 0x6000579, 0x0, 0x0, 0x0, 0x0, 0x600057F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000585, 0x0, 0x0, 0x0, 0x0, 0x600058B, 0x0, 0x0, 0x0, 0x0, 0x6000591, 0x0, 0x0, 0x0, 0x0, 0x6000597, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x600059D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60005A3, 0x0, 0x60005A9, 0x60005AF, 0x0, 0x60005B5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60005BB, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60005C1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60005C7, 0x0, 0x0, 0x0, 0x0, 0x60005CD, 0x0, 0x0, 0x0, 0x0, 0x60005D3, 0x0, 0x0, 0x0, 0x0, 0x60005D9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60005DF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60005E5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60005EB, 0x0, 0x60005F1, 0x0, 0x60005F7, 0x0, 0x60005FD, 0x0, 0x6000603, 0x0, 0x0, 0x0, 0x6000609, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x600060F, 0x0, 0x6000615, 0x0, 0x0, 0x600061B, 0x6000621, 0x0, 0x6000627, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x300062D, 0x3000630, 0x3000633, 0x3000636, 0x3000639, 0x300063C, 0x300063F, 0x3000642, 0x5000645, 0x500064A, 0x300064F, 0x3000652, 0x3000655, 0x3000658, 0x300065B, 0x300065E, 0x3000661, 0x3000664, 0x3000667, 0x300066A, 0x500066D, 0x5000672, 0x5000677, 0x500067C, 0x3000681, 0x3000684, 0x3000687, 0x300068A, 0x500068D, 0x5000692, 0x3000697, 0x300069A, 0x300069D, 0x30006A0, 0x30006A3, 0x30006A6, 0x30006A9, 0x30006AC, 0x30006AF, 0x30006B2, 0x30006B5, 0x30006B8, 0x30006BB, 0x30006BE, 0x30006C1, 0x30006C4, 0x50006C7, 0x50006CC, 0x30006D1, 0x30006D4, 0x30006D7, 0x30006DA, 0x30006DD, 0x30006E0, 0x30006E3, 0x30006E6, 0x50006E9, 0x50006EE, 0x30006F3, 0x30006F6, 0x30006F9, 0x30006FC, 0x30006FF, 0x3000702, 0x3000705, 0x3000708, 0x300070B, 0x300070E, 0x3000711, 0x3000714, 0x3000717, 0x300071A, 0x300071D, 0x3000720, 0x3000723, 0x3000726, 0x5000729, 0x500072E, 0x5000733, 0x5000738, 0x500073D, 0x5000742, 0x5000747, 0x500074C, 0x3000751, 0x3000754, 0x3000757, 0x300075A, 0x300075D, 0x3000760, 0x3000763, 0x3000766, 0x5000769, 0x500076E, 0x3000773, 0x3000776, 0x3000779, 0x300077C, 0x300077F, 0x3000782, 0x5000785, 0x500078A, 0x500078F, 0x5000794, 0x5000799, 0x500079E, 0x30007A3, 0x30007A6, 0x30007A9, 0x30007AC, 0x30007AF, 0x30007B2, 0x30007B5, 0x30007B8, 0x30007BB, 0x30007BE, 0x30007C1, 0x30007C4, 0x30007C7, 0x30007CA, 0x50007CD, 0x50007D2, 0x50007D7, 0x50007DC, 0x30007E1, 0x30007E4, 0x30007E7, 0x30007EA, 0x30007ED, 0x30007F0, 0x30007F3, 0x30007F6, 0x30007F9, 0x30007FC, 0x30007FF, 0x3000802, 0x3000805, 0x3000808, 0x300080B, 0x300080E, 0x3000811, 0x3000814, 0x3000817, 0x300081A, 0x300081D, 0x3000820, 0x3000823, 0x3000826, 0x3000829, 0x300082C, 0x300082F, 0x3000832, 0x3000835, 0x3000838, 0x0, 0x400083B, 0x0, 0x0, 0x0, 0x0, 0x300083F, 0x3000842, 0x3000845, 0x3000848, 0x500084B, 0x5000850, 0x5000855, 0x500085A, 0x500085F, 0x5000864, 0x5000869, 0x500086E, 0x5000873, 0x5000878, 0x500087D, 0x5000882, 0x5000887, 0x500088C, 0x5000891, 0x5000896, 0x500089B, 0x50008A0, 0x50008A5, 0x50008AA, 0x30008AF, 0x30008B2, 0x30008B5, 0x30008B8, 0x30008BB, 0x30008BE, 0x50008C1, 0x50008C6, 0x50008CB, 0x50008D0, 0x50008D5, 0x50008DA, 0x50008DF, 0x50008E4, 0x50008E9, 0x50008EE, 0x30008F3, 0x30008F6, 0x30008F9, 0x30008FC, 0x30008FF, 0x3000902, 0x3000905, 0x3000908, 0x500090B, 0x5000910, 0x5000915, 0x500091A, 0x500091F, 0x5000924, 0x5000929, 0x500092E, 0x5000933, 0x5000938, 0x500093D, 0x5000942, 0x5000947, 0x500094C, 0x5000951, 0x5000956, 0x500095B, 0x5000960, 0x5000965, 0x500096A, 0x300096F, 0x3000972, 0x3000975, 0x3000978, 0x500097B, 0x5000980, 0x5000985, 0x500098A, 0x500098F, 0x5000994, 0x5000999, 0x500099E, 0x50009A3, 0x50009A8, 0x30009AD, 0x30009B0, 0x30009B3, 0x30009B6, 0x30009B9, 0x30009BC, 0x30009BF, 0x30009C2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40009C5, 0x40009C9, 0x60009CD, 0x60009D3, 0x60009D9, 0x60009DF, 0x60009E5, 0x60009EB, 0x40009F1, 0x40009F5, 0x60009F9, 0x60009FF, 0x6000A05, 0x6000A0B, 0x6000A11, 0x6000A17, 0x4000A1D, 0x4000A21, 0x6000A25, 0x6000A2B, 0x6000A31, 0x6000A37, 0x0, 0x0, 0x4000A3D, 0x4000A41, 0x6000A45, 0x6000A4B, 0x6000A51, 0x6000A57, 0x0, 0x0, 0x4000A5D, 0x4000A61, 0x6000A65, 0x6000A6B, 0x6000A71, 0x6000A77, 0x6000A7D, 0x6000A83, 0x4000A89, 0x4000A8D, 0x6000A91, 0x6000A97, 0x6000A9D, 0x6000AA3, 0x6000AA9, 0x6000AAF, 0x4000AB5, 0x4000AB9, 0x6000ABD, 0x6000AC3, 0x6000AC9, 0x6000ACF, 0x6000AD5, 0x6000ADB, 0x4000AE1, 0x4000AE5, 0x6000AE9, 0x6000AEF, 0x6000AF5, 0x6000AFB, 0x6000B01, 0x6000B07, 0x4000B0D, 0x4000B11, 0x6000B15, 0x6000B1B, 0x6000B21, 0x6000B27, 0x0, 0x0, 0x4000B2D, 0x4000B31, 0x6000B35, 0x6000B3B, 0x6000B41, 0x6000B47, 0x0, 0x0, 0x4000B4D, 0x4000B51, 0x6000B55, 0x6000B5B, 0x6000B61, 0x6000B67, 0x6000B6D, 0x6000B73, 0x0, 0x4000B79, 0x0, 0x6000B7D, 0x0, 0x6000B83, 0x0, 0x6000B89, 0x4000B8F, 0x4000B93, 0x6000B97, 0x6000B9D, 0x6000BA3, 0x6000BA9, 0x6000BAF, 0x6000BB5, 0x4000BBB, 0x4000BBF, 0x6000BC3, 0x6000BC9, 0x6000BCF, 0x6000BD5, 0x6000BDB, 0x6000BE1, 0x4000BE7, 0x4000357, 0x4000BEB, 0x400035B, 0x4000BEF, 0x400035F, 0x4000BF3, 0x4000363, 0x4000BF7, 0x400036D, 0x4000BFB, 0x4000371, 0x4000BFF, 0x4000375, 0x0, 0x0, 0x6000C03, 0x6000C09, 0x8000C0F, 0x8000C17, 0x8000C1F, 0x8000C27, 0x8000C2F, 0x8000C37, 0x6000C3F, 0x6000C45, 0x8000C4B, 0x8000C53, 0x8000C5B, 0x8000C63, 0x8000C6B, 0x8000C73, 0x6000C7B, 0x6000C81, 0x8000C87, 0x8000C8F, 0x8000C97, 0x8000C9F, 0x8000CA7, 0x8000CAF, 0x6000CB7, 0x6000CBD, 0x8000CC3, 0x8000CCB, 0x8000CD3, 0x8000CDB, 0x8000CE3, 0x8000CEB, 0x6000CF3, 0x6000CF9, 0x8000CFF, 0x8000D07, 0x8000D0F, 0x8000D17, 0x8000D1F, 0x8000D27, 0x6000D2F, 0x6000D35, 0x8000D3B, 0x8000D43, 0x8000D4B, 0x8000D53, 0x8000D5B, 0x8000D63, 0x4000D6B, 0x4000D6F, 0x6000D73, 0x4000D79, 0x6000D7D, 0x0, 0x4000D83, 0x6000D87, 0x4000D8D, 0x4000D91, 0x4000D95, 0x400032B, 0x4000D99, 0x0, 0x2000349, 0x0, 0x0, 0x4000D9D, 0x6000DA1, 0x4000DA7, 0x6000DAB, 0x0, 0x4000DB1, 0x6000DB5, 0x4000DBB, 0x4000331, 0x4000DBF, 0x4000335, 0x4000DC3, 0x5000DC7, 0x5000DCC, 0x5000DD1, 0x4000DD6, 0x4000DDA, 0x6000DDE, 0x6000349, 0x0, 0x0, 0x4000DE4, 0x6000DE8, 0x4000DEE, 0x4000DF2, 0x4000DF6, 0x4000339, 0x0, 0x5000DFA, 0x5000DFF, 0x5000E04, 0x4000E09, 0x4000E0D, 0x6000E11, 0x6000367, 0x4000E17, 0x4000E1B, 0x4000E1F, 0x6000E23, 0x4000E29, 0x4000E2D, 0x4000E31, 0x4000341, 0x4000E35, 0x4000E39, 0x4000327, 0x1000E3D, 0x0, 0x0, 0x6000E3E, 0x4000E44, 0x6000E48, 0x0, 0x4000E4E, 0x6000E52, 0x4000E58, 0x400033D, 0x4000E5C, 0x4000345, 0x4000E60, 0x2000E64, 0x0, 0x0, 0x3000E66, 0x3000E69, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000345, 0x0, 0x0, 0x0, 0x100012C, 0x300000F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5000E6C, 0x5000E71, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5000E76, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5000E7B, 0x5000E80, 0x5000E85, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5000E8A, 0x0, 0x0, 0x0, 0x0, 0x5000E8F, 0x0, 0x0, 0x5000E94, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5000E99, 0x0, 0x5000E9E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5000EA3, 0x0, 0x0, 0x5000EA8, 0x0, 0x0, 0x5000EAD, 0x0, 0x5000EB2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3000EB7, 0x0, 0x5000EBA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5000EBF, 0x3000EC4, 0x3000EC7, 0x5000ECA, 0x5000ECF, 0x0, 0x0, 0x5000ED4, 0x5000ED9, 0x0, 0x0, 0x5000EDE, 0x5000EE3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5000EE8, 0x5000EED, 0x0, 0x0, 0x5000EF2, 0x5000EF7, 0x0, 0x0, 0x5000EFC, 0x5000F01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5000F06, 0x5000F0B, 0x5000F10, 0x5000F15, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5000F1A, 0x5000F1F, 0x5000F24, 0x5000F29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5000F2E, 0x5000F33, 0x5000F38, 0x5000F3D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3000F42, 0x3000F45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5000F48, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000F4D, 0x0, 0x6000F53, 0x0, 0x6000F59, 0x0, 0x6000F5F, 0x0, 0x6000F65, 0x0, 0x6000F6B, 0x0, 0x6000F71, 0x0, 0x6000F77, 0x0, 0x6000F7D, 0x0, 0x6000F83, 0x0, 0x6000F89, 0x0, 0x6000F8F, 0x0, 0x0, 0x6000F95, 0x0, 0x6000F9B, 0x0, 0x6000FA1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000FA7, 0x6000FAD, 0x0, 0x6000FB3, 0x6000FB9, 0x0, 0x6000FBF, 0x6000FC5, 0x0, 0x6000FCB, 0x6000FD1, 0x0, 0x6000FD7, 0x6000FDD, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000FE3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000FE9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000FEF, 0x0, 0x6000FF5, 0x0, 0x6000FFB, 0x0, 0x6001001, 0x0, 0x6001007, 0x0, 0x600100D, 0x0, 0x6001013, 0x0, 0x6001019, 0x0, 0x600101F, 0x0, 0x6001025, 0x0, 0x600102B, 0x0, 0x6001031, 0x0, 0x0, 0x6001037, 0x0, 0x600103D, 0x0, 0x6001043, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6001049, 0x600104F, 0x0, 0x6001055, 0x600105B, 0x0, 0x6001061, 0x6001067, 0x0, 0x600106D, 0x6001073, 0x0, 0x6001079, 0x600107F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6001085, 0x0, 0x0, 0x600108B, 0x6001091, 0x6001097, 0x600109D, 0x0, 0x0, 0x0, 0x60010A3, 0x0, 0x30010A9, 0x30010AC, 0x30010AF, 0x30010B2, 0x30010B5, 0x30010B8, 0x30010BB, 0x30010BE, 0x30010BE, 0x30010C1, 0x30010C4, 0x30010C7, 0x30010CA, 0x30010CD, 0x30010D0, 0x30010D3, 0x30010D6, 0x30010D9, 0x30010DC, 0x30010DF, 0x30010E2, 0x30010E5, 0x30010E8, 0x30010EB, 0x30010EE, 0x30010F1, 0x30010F4, 0x30010F7, 0x30010FA, 0x30010FD, 0x3001100, 0x3001103, 0x3001106, 0x3001109, 0x300110C, 0x300110F, 0x3001112, 0x3001115, 0x3001118, 0x300111B, 0x300111E, 0x3001121, 0x3001124, 0x3001127, 0x300112A, 0x300112D, 0x3001130, 0x3001133, 0x3001136, 0x3001139, 0x300113C, 0x300113F, 0x3001142, 0x3001145, 0x3001148, 0x300114B, 0x300114E, 0x3001151, 0x3001154, 0x3001157, 0x300115A, 0x300115D, 0x3001160, 0x3001163, 0x3001166, 0x3001169, 0x300116C, 0x300116F, 0x3001172, 0x3001175, 0x3001178, 0x300117B, 0x300117E, 0x3001181, 0x3001184, 0x3001187, 0x300118A, 0x300118D, 0x3001190, 0x3001193, 0x3001196, 0x3001199, 0x300119C, 0x300119F, 0x30011A2, 0x30011A5, 0x30011A8, 0x30011AB, 0x30011AE, 0x30011B1, 0x30011B4, 0x30011B7, 0x30010E2, 0x30011BA, 0x30011BD, 0x30011C0, 0x30011C3, 0x30011C6, 0x30011C9, 0x30011CC, 0x30011CF, 0x30011D2, 0x30011D5, 0x30011D8, 0x30011DB, 0x30011DE, 0x30011E1, 0x30011E4, 0x30011E7, 0x30011EA, 0x30011ED, 0x30011F0, 0x30011F3, 0x30011F6, 0x30011F9, 0x30011FC, 0x30011FF, 0x3001202, 0x3001205, 0x3001208, 0x300120B, 0x300120E, 0x3001211, 0x3001214, 0x3001217, 0x300121A, 0x300121D, 0x3001220, 0x3001223, 0x3001226, 0x3001229, 0x300122C, 0x300122F, 0x3001232, 0x3001235, 0x3001238, 0x300123B, 0x300123E, 0x3001241, 0x3001244, 0x3001247, 0x300124A, 0x300124D, 0x3001250, 0x3001253, 0x3001256, 0x3001259, 0x300125C, 0x300125F, 0x3001262, 0x3001265, 0x3001268, 0x300126B, 0x300126E, 0x3001271, 0x3001274, 0x3001277, 0x300127A, 0x300127D, 0x3001280, 0x3001283, 0x30011F0, 0x3001286, 0x3001289, 0x300128C, 0x300128F, 0x3001292, 0x3001295, 0x3001298, 0x300129B, 0x30011C0, 0x300129E, 0x30012A1, 0x30012A4, 0x30012A7, 0x30012AA, 0x30012AD, 0x30012B0, 0x30012B3, 0x30012B6, 0x30012B9, 0x30012BC, 0x30012BF, 0x30012C2, 0x30012C5, 0x30012C8, 0x30012CB, 0x30012CE, 0x30012D1, 0x30012D4, 0x30012D7, 0x30010E2, 0x30012DA, 0x30012DD, 0x30012E0, 0x30012E3, 0x30012E6, 0x30012E9, 0x30012EC, 0x30012EF, 0x30012F2, 0x30012F5, 0x30012F8, 0x30012FB, 0x30012FE, 0x3001301, 0x3001304, 0x3001307, 0x300130A, 0x300130D, 0x3001310, 0x3001313, 0x3001316, 0x3001319, 0x300131C, 0x300131F, 0x3001322, 0x3001325, 0x3001328, 0x30011C6, 0x300132B, 0x300132E, 0x3001331, 0x3001334, 0x3001337, 0x300133A, 0x300133D, 0x3001340, 0x3001343, 0x3001346, 0x3001349, 0x300134C, 0x300134F, 0x3001352, 0x3001355, 0x3001358, 0x300135B, 0x300135E, 0x3001361, 0x3001364, 0x3001367, 0x300136A, 0x300136D, 0x3001370, 0x3001373, 0x3001376, 0x3001379, 0x300137C, 0x300137F, 0x3001382, 0x3001385, 0x3001388, 0x300138B, 0x300138E, 0x3001391, 0x3001394, 0x3001397, 0x300139A, 0x300139D, 0x30013A0, 0x30013A3, 0x30013A6, 0x30013A9, 0x30013AC, 0x30013AF, 0x30013B2, 0x30013B5, 0x30013B8, 0x30013BB, 0x30013BE, 0x0, 0x0, 0x30013C1, 0x0, 0x30013C4, 0x0, 0x0, 0x30013C7, 0x30013CA, 0x30013CD, 0x30013D0, 0x30013D3, 0x30013D6, 0x30013D9, 0x30013DC, 0x30013DF, 0x30013E2, 0x0, 0x30013E5, 0x0, 0x30013E8, 0x0, 0x0, 0x30013EB, 0x30013EE, 0x0, 0x0, 0x0, 0x30013F1, 0x30013F4, 0x30013F7, 0x30013FA, 0x30013FD, 0x3001400, 0x3001403, 0x3001406, 0x3001409, 0x300140C, 0x300140F, 0x3001412, 0x3001415, 0x3001418, 0x300141B, 0x300141E, 0x3001421, 0x3001424, 0x3001427, 0x300142A, 0x300142D, 0x3001430, 0x3001433, 0x3001436, 0x3001439, 0x300143C, 0x300143F, 0x3001442, 0x3001445, 0x3001448, 0x300144B, 0x300144E, 0x3001451, 0x3001454, 0x3001457, 0x300145A, 0x300145D, 0x3001460, 0x3001463, 0x3001466, 0x3001469, 0x300146C, 0x300146F, 0x3001472, 0x3001475, 0x3001265, 0x3001478, 0x300147B, 0x300147E, 0x3001481, 0x3001484, 0x3001487, 0x3001487, 0x300148A, 0x300148D, 0x3001490, 0x3001493, 0x3001496, 0x3001499, 0x300149C, 0x300149F, 0x30013EB, 0x30014A2, 0x30014A5, 0x30014A8, 0x30014AB, 0x40014AE, 0x30014B2, 0x0, 0x0, 0x30014B5, 0x30014B8, 0x30014BB, 0x30014BE, 0x30014C1, 0x30014C4, 0x30014C7, 0x30014CA, 0x3001415, 0x30014CD, 0x30014D0, 0x30014D3, 0x30013C1, 0x30014D6, 0x30014D9, 0x30014DC, 0x30014DF, 0x30014E2, 0x30014E5, 0x30014E8, 0x30014EB, 0x30014EE, 0x30014F1, 0x30014F4, 0x30014F7, 0x3001430, 0x30014FA, 0x3001433, 0x30014FD, 0x3001500, 0x3001503, 0x3001506, 0x3001509, 0x30013C4, 0x3001121, 0x300150C, 0x300150F, 0x3001512, 0x30011F3, 0x30012F8, 0x3001515, 0x3001518, 0x3001448, 0x300151B, 0x300144B, 0x300151E, 0x3001521, 0x3001524, 0x30013CA, 0x3001527, 0x300152A, 0x300152D, 0x3001530, 0x3001533, 0x30013CD, 0x3001536, 0x3001539, 0x300153C, 0x300153F, 0x3001542, 0x3001545, 0x3001475, 0x3001548, 0x300154B, 0x3001265, 0x300154E, 0x3001481, 0x3001551, 0x3001554, 0x3001557, 0x300155A, 0x300155D, 0x3001490, 0x3001560, 0x30013E8, 0x3001563, 0x3001493, 0x30011BA, 0x3001566, 0x3001496, 0x3001569, 0x300149C, 0x300156C, 0x300156F, 0x3001572, 0x3001575, 0x3001578, 0x30014A2, 0x30013DC, 0x300157B, 0x30014A5, 0x300157E, 0x30014A8, 0x3001581, 0x30010BE, 0x4001584, 0x4001588, 0x400158C, 0x3001590, 0x3001593, 0x3001596, 0x4001599, 0x400159D, 0x40015A1, 0x30015A5, 0x30015A8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40015AB, 0x0, 0x40015AF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40015B3, 0x40015B7, 0x60015BB, 0x60015C1, 0x40015C7, 0x40015CB, 0x40015CF, 0x40015D3, 0x40015D7, 0x40015DB, 0x40015DF, 0x40015E3, 0x40015E7, 0x0, 0x40015EB, 0x40015EF, 0x40015F3, 0x40015F7, 0x40015FB, 0x0, 0x40015FF, 0x0, 0x4001603, 0x4001607, 0x0, 0x400160B, 0x400160F, 0x0, 0x4001613, 0x4001617, 0x400161B, 0x40015BB, 0x400161F, 0x4001623, 0x4001627, 0x400162B, 0x400162F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8001633, 0x0, 0x800163B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8001643, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x800164B, 0x8001653, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x800165B, 0x8001663, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x800166B, 0x8001673, 0x0, 0x800167B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8001683, 0x800168B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8001693, 0x800169B, 0xC0016A3, 0xC0016AF, 0xC0016BB, 0xC0016C7, 0xC0016D3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80016DF, 0x80016E7, 0xC0016EF, 0xC0016FB, 0xC001707, 0xC001713, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x300171F, 0x3001722, 0x3001725, 0x4001728, 0x300172C, 0x3001403, 0x300172F, 0x3001732, 0x3001735, 0x3001738, 0x3001406, 0x300173B, 0x300173E, 0x4001741, 0x3001409, 0x3001745, 0x3001748, 0x300174B, 0x400174E, 0x3001752, 0x3001755, 0x3001758, 0x400175B, 0x300175F, 0x3001762, 0x3001765, 0x3001768, 0x30014B8, 0x400176B, 0x300176F, 0x3001772, 0x3001775, 0x3001778, 0x300177B, 0x300177E, 0x3001781, 0x3001784, 0x30014C7, 0x300140C, 0x300140F, 0x30014CA, 0x3001787, 0x300178A, 0x30011CC, 0x300178D, 0x3001412, 0x3001790, 0x3001793, 0x3001796, 0x3001799, 0x3001799, 0x3001799, 0x400179C, 0x30017A0, 0x30017A3, 0x30017A6, 0x40017A9, 0x30017AD, 0x30017B0, 0x30017B3, 0x30017B6, 0x30017B9, 0x30017BC, 0x30017BF, 0x30017C2, 0x30017C5, 0x30017C8, 0x30017CB, 0x30017CE, 0x30017D1, 0x30017D1, 0x30014D0, 0x30017D4, 0x30017D7, 0x30017DA, 0x30017DD, 0x3001418, 0x30017E0, 0x30017E3, 0x30017E6, 0x3001397, 0x30017E9, 0x30017EC, 0x30017EF, 0x30017F2, 0x30017F5, 0x30017F8, 0x30017FB, 0x30017FE, 0x4001801, 0x3001805, 0x3001808, 0x300180B, 0x300180E, 0x3001811, 0x3001814, 0x4001817, 0x400181B, 0x300181F, 0x3001822, 0x3001825, 0x3001828, 0x300182B, 0x300182E, 0x3001831, 0x3001834, 0x3001837, 0x3001837, 0x400183A, 0x300183E, 0x3001841, 0x30011C0, 0x3001844, 0x4001847, 0x300184B, 0x300184E, 0x3001851, 0x3001854, 0x3001857, 0x300185A, 0x3001427, 0x300185D, 0x3001860, 0x4001863, 0x3001867, 0x400186A, 0x300186E, 0x3001871, 0x3001874, 0x3001877, 0x300187A, 0x300187D, 0x3001880, 0x3001883, 0x3001886, 0x3001889, 0x300188C, 0x400188F, 0x3001893, 0x3001896, 0x3001899, 0x300189C, 0x300111E, 0x400189F, 0x30018A3, 0x40018A6, 0x40018A6, 0x30018AA, 0x30018AD, 0x30018AD, 0x30018B0, 0x40018B3, 0x40018B7, 0x30018BB, 0x30018BE, 0x30018C1, 0x30018C4, 0x30018C7, 0x30018CA, 0x30018CD, 0x30018D0, 0x30018D3, 0x30018D6, 0x300142A, 0x40018D9, 0x30018DD, 0x30018E0, 0x30018E3, 0x30014F4, 0x30018E3, 0x30018E6, 0x3001430, 0x30018E9, 0x30018EC, 0x30018EF, 0x30018F2, 0x3001433, 0x30010CD, 0x30018F5, 0x30018F8, 0x30018FB, 0x30018FE, 0x3001901, 0x3001904, 0x4001907, 0x300190B, 0x300190E, 0x3001911, 0x3001914, 0x3001917, 0x400191A, 0x300191E, 0x3001921, 0x3001924, 0x3001927, 0x300192A, 0x300192D, 0x3001930, 0x3001933, 0x3001936, 0x3001436, 0x3001939, 0x400193C, 0x3001940, 0x3001943, 0x3001946, 0x3001949, 0x300143C, 0x300194C, 0x300194F, 0x3001952, 0x3001955, 0x3001958, 0x300195B, 0x300195E, 0x3001961, 0x3001121, 0x300150C, 0x3001964, 0x3001967, 0x300196A, 0x400196D, 0x3001971, 0x3001974, 0x3001977, 0x300197A, 0x300143F, 0x400197D, 0x3001981, 0x3001984, 0x3001987, 0x3001590, 0x300198A, 0x300198D, 0x3001990, 0x3001993, 0x4001996, 0x300199A, 0x300199D, 0x30019A0, 0x40019A3, 0x30019A7, 0x30019AA, 0x30019AD, 0x30019B0, 0x30011F3, 0x30019B3, 0x40019B6, 0x40019BA, 0x40019BE, 0x30019C2, 0x40019C5, 0x30019C9, 0x30019CC, 0x30019CF, 0x30019D2, 0x30019D5, 0x3001442, 0x30012F8, 0x30019D8, 0x30019DB, 0x30019DE, 0x40019E1, 0x30019E5, 0x30019E8, 0x30019EB, 0x30019EE, 0x3001518, 0x30019F1, 0x40019F4, 0x30019F8, 0x30019FB, 0x40019FE, 0x4001A02, 0x3001A06, 0x3001A09, 0x300151B, 0x3001A0C, 0x3001A0F, 0x3001A12, 0x3001A15, 0x3001A18, 0x3001A1B, 0x4001A1E, 0x3001A22, 0x4001A25, 0x3001A29, 0x4001A2C, 0x3001A30, 0x3001521, 0x3001A33, 0x4001A36, 0x3001A3A, 0x3001A3D, 0x4001A40, 0x4001A44, 0x3001A48, 0x3001A4B, 0x3001A4E, 0x3001A51, 0x3001A54, 0x3001A54, 0x3001A57, 0x3001A5A, 0x3001527, 0x3001A5D, 0x3001A60, 0x3001A63, 0x3001A66, 0x4001A69, 0x3001A6D, 0x4001A70, 0x30011C9, 0x4001A74, 0x3001A78, 0x4001A7B, 0x4001A7F, 0x4001A83, 0x3001A87, 0x3001A8A, 0x3001539, 0x4001A8D, 0x4001A91, 0x4001A95, 0x4001A99, 0x3001A9D, 0x3001AA0, 0x3001AA0, 0x300153C, 0x3001596, 0x3001AA3, 0x3001AA6, 0x3001AA9, 0x4001AAC, 0x3001AB0, 0x3001157, 0x3001542, 0x3001AB3, 0x4001AB6, 0x3001463, 0x4001ABA, 0x4001ABE, 0x30013D9, 0x3001AC2, 0x3001AC5, 0x300146F, 0x3001AC8, 0x3001ACB, 0x4001ACE, 0x4001AD2, 0x4001AD2, 0x3001AD6, 0x3001AD9, 0x4001ADC, 0x3001AE0, 0x3001AE3, 0x3001AE6, 0x4001AE9, 0x3001AED, 0x3001AF0, 0x3001AF3, 0x3001AF6, 0x3001AF9, 0x4001AFC, 0x3001B00, 0x3001B03, 0x3001B06, 0x3001B09, 0x3001B0C, 0x3001B0F, 0x4001B12, 0x4001B16, 0x3001B1A, 0x4001B1D, 0x3001B21, 0x4001B24, 0x3001B28, 0x3001B2B, 0x3001481, 0x4001B2E, 0x4001B32, 0x3001B36, 0x4001B39, 0x3001B3D, 0x4001B40, 0x3001B44, 0x3001B47, 0x3001B4A, 0x3001B4D, 0x3001B50, 0x3001B53, 0x4001B56, 0x4001B5A, 0x4001B5E, 0x4001B62, 0x30018AA, 0x3001B66, 0x3001B69, 0x3001B6C, 0x3001B6F, 0x3001B72, 0x3001B75, 0x3001B78, 0x3001B7B, 0x3001B7E, 0x3001B81, 0x3001B84, 0x4001B87, 0x30011FF, 0x3001B8B, 0x3001B8E, 0x3001B91, 0x3001B94, 0x3001B97, 0x3001B9A, 0x300148A, 0x3001B9D, 0x3001BA0, 0x3001BA3, 0x3001BA6, 0x4001BA9, 0x4001BAD, 0x4001BB1, 0x3001BB5, 0x3001BB8, 0x3001BBB, 0x3001BBE, 0x4001BC1, 0x3001BC5, 0x4001BC8, 0x3001BCC, 0x3001BCF, 0x4001BD2, 0x4001BD6, 0x3001BDA, 0x3001BDD, 0x3001148, 0x3001BE0, 0x3001BE3, 0x3001BE6, 0x3001BE9, 0x3001BEC, 0x3001BEF, 0x3001557, 0x3001BF2, 0x3001BF5, 0x3001BF8, 0x3001BFB, 0x3001BFE, 0x3001C01, 0x3001C04, 0x3001C07, 0x3001C0A, 0x4001C0D, 0x3001C11, 0x3001C14, 0x3001C17, 0x3001C1A, 0x3001C1D, 0x4001C20, 0x4001C24, 0x3001C28, 0x3001C2B, 0x3001C2E, 0x3001566, 0x3001569, 0x3001C31, 0x4001C34, 0x3001C38, 0x3001C3B, 0x3001C3E, 0x3001C41, 0x4001C44, 0x4001C48, 0x3001C4C, 0x3001C4F, 0x3001C52, 0x4001C55, 0x3001C59, 0x300156C, 0x4001C5C, 0x4001C60, 0x3001C64, 0x3001C67, 0x3001C6A, 0x4001C6D, 0x3001C71, 0x3001C74, 0x3001C77, 0x3001C7A, 0x3001C7D, 0x3001C80, 0x3001C83, 0x4001C86, 0x3001C8A, 0x3001C8D, 0x3001C90, 0x4001C93, 0x3001C97, 0x3001C9A, 0x3001C9D, 0x3001CA0, 0x4001CA3, 0x4001CA7, 0x3001CAB, 0x3001CAE, 0x3001CB1, 0x4001CB4, 0x3001CB8, 0x4001CBB, 0x300157E, 0x300157E, 0x3001CBF, 0x4001CC2, 0x3001CC6, 0x3001CC9, 0x3001CCC, 0x3001CCF, 0x3001CD2, 0x3001CD5, 0x3001CD8, 0x4001CDB, 0x3001581, 0x3001CDF, 0x3001CE2, 0x3001CE5, 0x3001CE8, 0x3001CEB, 0x4001CEE, 0x3001CF2, 0x4001CF5, 0x4001CF9, 0x4001CFD, 0x3001D01, 0x3001D04, 0x3001D07, 0x3001D0A, 0x3001D0D, 0x3001D10, 0x3001D13, 0x3001D16, 0x4001D19, 0x0, 0x0, }; const uint32_t* NFDDataPtr = NFDData; const uint32_t NFKDIndex1[272] = { 0, 128, 256, 384, 512, 416, 416, 416, 416, 416, 640, 416, 416, 416, 416, 768, 416, 896, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 1024, 1152, 1280, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 1408, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, }; const uint32_t* NFKDIndex1Ptr = NFKDIndex1; const uint32_t NFKDIndex2[1536] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0, 0x0, 0x100, 0x120, 0x140, 0x160, 0x180, 0x0, 0x0, 0x0, 0x1A0, 0x1C0, 0x1E0, 0x0, 0x0, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, 0x300, 0x320, 0x0, 0x0, 0x340, 0x360, 0x0, 0x0, 0x0, 0x0, 0x380, 0x0, 0x0, 0x0, 0x0, 0x3A0, 0x0, 0x3C0, 0x0, 0x0, 0x3E0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x400, 0x420, 0x0, 0x0, 0x0, 0x440, 0x0, 0x0, 0x460, 0x480, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4A0, 0x0, 0x4C0, 0x0, 0x4E0, 0x0, 0x0, 0x0, 0x500, 0x0, 0x0, 0x0, 0x520, 0x0, 0x0, 0x0, 0x540, 0x0, 0x0, 0x0, 0x560, 0x0, 0x0, 0x580, 0x0, 0x0, 0x0, 0x5A0, 0x5C0, 0x0, 0x5E0, 0x0, 0x600, 0x620, 0x640, 0x660, 0x0, 0x0, 0x0, 0x680, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6A0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6C0, 0x6E0, 0x700, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x720, 0x740, 0x760, 0x780, 0x7A0, 0x0, 0x0, 0x7C0, 0x7E0, 0x800, 0x820, 0x840, 0x860, 0x880, 0x8A0, 0x8C0, 0x8E0, 0x900, 0x920, 0x940, 0x960, 0x980, 0x9A0, 0x9C0, 0x9E0, 0xA00, 0xA20, 0xA40, 0xA60, 0x0, 0x0, 0xA80, 0xAA0, 0xAC0, 0xAE0, 0xB00, 0xB20, 0xB40, 0x0, 0xB60, 0xB80, 0xBA0, 0xBC0, 0xBE0, 0xC00, 0x0, 0xC20, 0x0, 0xC40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xC60, 0xC80, 0xCA0, 0xCC0, 0xCE0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xD00, 0x0, 0x0, 0xD20, 0x0, 0x0, 0xD40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xD60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xD80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xDA0, 0x0, 0x0, 0xDC0, 0xDE0, 0xE00, 0xE20, 0xE40, 0xE60, 0xE80, 0xEA0, 0x0, 0xEC0, 0xEE0, 0xF00, 0xF20, 0xF40, 0xF60, 0xF80, 0xFA0, 0x0, 0xFC0, 0xFE0, 0x1000, 0x1020, 0x0, 0x0, 0x0, 0x1040, 0x1060, 0x1080, 0x10A0, 0x10C0, 0x10E0, 0x1100, 0x1120, 0x1140, 0x1160, 0x1180, 0x11A0, 0x11C0, 0x11E0, 0x1200, 0x1220, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1240, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1260, 0x0, 0x0, 0x0, 0x1280, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12A0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12C0, 0x12E0, 0x1300, 0x1320, 0x1340, 0x1360, 0x1380, 0x13A0, 0x13C0, 0x13E0, 0x1400, 0x1420, 0x1440, 0x1460, 0x1480, 0x0, 0x14A0, 0x14C0, 0x14E0, 0x1500, 0x1520, 0x1540, 0x1560, 0x1580, 0x15A0, 0x15C0, 0x15E0, 0x1600, 0x1620, 0x1640, 0x1660, 0x1680, 0x16A0, 0x16C0, 0x16E0, 0x1700, 0x1720, 0x1740, 0x1760, 0x1780, 0x17A0, 0x17C0, 0x17E0, 0x1800, 0x1820, 0x1840, 0x1860, 0x1880, 0x18A0, 0x18C0, 0x18E0, 0x1900, 0x1920, 0x1940, 0x1960, 0x1980, 0x0, 0x0, 0x0, 0x0, 0x19A0, 0x19C0, 0x0, 0x0, 0x0, 0x19E0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1A00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1A20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1A40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1A60, 0x1A80, 0x0, 0x1AA0, 0x1AC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xCB6, 0x1AE0, 0x1B00, 0x1AEC, 0x1B20, 0x1B40, 0x1B60, 0xCC6, 0x1B80, 0x1BA0, 0x1BC0, 0x1AE8, 0xCCA, 0xCB6, 0x1AE0, 0xCC2, 0x1AEC, 0x1BE0, 0xCBA, 0x1AE4, 0xCC6, 0x1C00, 0x1C20, 0x1C40, 0x1C26, 0x1C0C, 0x1C2C, 0x1C12, 0x1C32, 0x1C18, 0x1C60, 0x1C80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1CA0, 0x1CC0, 0x1CE0, 0x1D00, 0x1D20, 0x1D40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1D60, 0x1D80, 0x1DA0, 0x1DC0, 0x1DE0, 0x0, 0x0, 0x0, 0x1E00, 0x1E20, 0x1E40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1E60, 0x1E80, 0x1EA0, 0x1EC0, 0x1EE0, 0x1F00, 0x1F20, 0x1F40, 0x1F60, 0x1F80, 0x1FA0, 0x1FC0, 0x1FE0, 0x2000, 0x2020, 0x2040, 0x2060, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, }; const uint32_t* NFKDIndex2Ptr = NFKDIndex2; const uint32_t NFKDData[8320] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1001D1D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3001D1E, 0x0, 0x100004E, 0x0, 0x0, 0x0, 0x0, 0x3001D21, 0x0, 0x0, 0x1001D24, 0x1001D25, 0x3001D26, 0x2001D29, 0x0, 0x0, 0x3001D2B, 0x1001D2E, 0x100007E, 0x0, 0x5001D2F, 0x5001D34, 0x5001D39, 0x0, 0x3000000, 0x3000003, 0x3000006, 0x3000009, 0x300000C, 0x300000F, 0x0, 0x3000012, 0x3000015, 0x3000018, 0x300001B, 0x300001E, 0x3000021, 0x3000024, 0x3000027, 0x300002A, 0x0, 0x300002D, 0x3000030, 0x3000033, 0x3000036, 0x3000039, 0x300003C, 0x0, 0x0, 0x300003F, 0x3000042, 0x3000045, 0x3000048, 0x300004B, 0x0, 0x0, 0x300004E, 0x3000051, 0x3000054, 0x3000057, 0x300005A, 0x300005D, 0x0, 0x3000060, 0x3000063, 0x3000066, 0x3000069, 0x300006C, 0x300006F, 0x3000072, 0x3000075, 0x3000078, 0x0, 0x300007B, 0x300007E, 0x3000081, 0x3000084, 0x3000087, 0x300008A, 0x0, 0x0, 0x300008D, 0x3000090, 0x3000093, 0x3000096, 0x3000099, 0x0, 0x300009C, 0x300009F, 0x30000A2, 0x30000A5, 0x30000A8, 0x30000AB, 0x30000AE, 0x30000B1, 0x30000B4, 0x30000B7, 0x30000BA, 0x30000BD, 0x30000C0, 0x30000C3, 0x30000C6, 0x30000C9, 0x30000CC, 0x0, 0x0, 0x30000CF, 0x30000D2, 0x30000D5, 0x30000D8, 0x30000DB, 0x30000DE, 0x30000E1, 0x30000E4, 0x30000E7, 0x30000EA, 0x30000ED, 0x30000F0, 0x30000F3, 0x30000F6, 0x30000F9, 0x30000FC, 0x30000FF, 0x3000102, 0x3000105, 0x3000108, 0x0, 0x0, 0x300010B, 0x300010E, 0x3000111, 0x3000114, 0x3000117, 0x300011A, 0x300011D, 0x3000120, 0x3000123, 0x0, 0x2001D3E, 0x2001D40, 0x3000126, 0x3000129, 0x300012C, 0x300012F, 0x0, 0x3000132, 0x3000135, 0x3000138, 0x300013B, 0x300013E, 0x3000141, 0x3001D42, 0x3001D45, 0x0, 0x0, 0x3000144, 0x3000147, 0x300014A, 0x300014D, 0x3000150, 0x3000153, 0x3001D48, 0x0, 0x0, 0x3000156, 0x3000159, 0x300015C, 0x300015F, 0x3000162, 0x3000165, 0x0, 0x0, 0x3000168, 0x300016B, 0x300016E, 0x3000171, 0x3000174, 0x3000177, 0x300017A, 0x300017D, 0x3000180, 0x3000183, 0x3000186, 0x3000189, 0x300018C, 0x300018F, 0x3000192, 0x3000195, 0x3000198, 0x300019B, 0x0, 0x0, 0x300019E, 0x30001A1, 0x30001A4, 0x30001A7, 0x30001AA, 0x30001AD, 0x30001B0, 0x30001B3, 0x30001B6, 0x30001B9, 0x30001BC, 0x30001BF, 0x30001C2, 0x30001C5, 0x30001C8, 0x30001CB, 0x30001CE, 0x30001D1, 0x30001D4, 0x30001D7, 0x30001DA, 0x30001DD, 0x30001E0, 0x100017D, 0x30001E3, 0x30001E6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30001E9, 0x30001EC, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4001D4B, 0x4001D4F, 0x4001D53, 0x2001D57, 0x2001D59, 0x2001D5B, 0x2001D5D, 0x2001D5F, 0x2001D61, 0x30001EF, 0x30001F2, 0x30001F5, 0x30001F8, 0x30001FB, 0x30001FE, 0x3000201, 0x3000204, 0x5000207, 0x500020C, 0x5000211, 0x5000216, 0x500021B, 0x5000220, 0x5000225, 0x500022A, 0x0, 0x500022F, 0x5000234, 0x5000239, 0x500023E, 0x4000243, 0x4000247, 0x0, 0x0, 0x300024B, 0x300024E, 0x3000251, 0x3000254, 0x3000257, 0x300025A, 0x500025D, 0x5000262, 0x4000267, 0x400026B, 0x300026F, 0x2001D4B, 0x2001D4F, 0x2001D53, 0x3000272, 0x3000275, 0x0, 0x0, 0x3000278, 0x300027B, 0x500027E, 0x5000283, 0x4000288, 0x400028C, 0x4000290, 0x4000294, 0x3000298, 0x300029B, 0x300029E, 0x30002A1, 0x30002A4, 0x30002A7, 0x30002AA, 0x30002AD, 0x30002B0, 0x30002B3, 0x30002B6, 0x30002B9, 0x30002BC, 0x30002BF, 0x30002C2, 0x30002C5, 0x30002C8, 0x30002CB, 0x30002CE, 0x30002D1, 0x30002D4, 0x30002D7, 0x30002DA, 0x30002DD, 0x30002E0, 0x30002E3, 0x30002E6, 0x30002E9, 0x0, 0x0, 0x30002EC, 0x30002EF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3000239, 0x300023E, 0x30002F2, 0x30002F5, 0x50002F8, 0x50002FD, 0x5000302, 0x5000307, 0x300030C, 0x300030F, 0x5000312, 0x5000317, 0x300031C, 0x300031F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000108, 0x2001D63, 0x1000129, 0x100016B, 0x2001D65, 0x2001D67, 0x2001D69, 0x10001C5, 0x1000099, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3001D6B, 0x3001D6E, 0x3001D71, 0x3001D74, 0x3001D77, 0x3001D7A, 0x0, 0x0, 0x2001D7D, 0x1000135, 0x100017D, 0x100080E, 0x2001D7F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000001, 0x2000004, 0x0, 0x2000322, 0x4000212, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000324, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3001D81, 0x0, 0x0, 0x0, 0x1000326, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3001D26, 0x5001D84, 0x400032B, 0x200032F, 0x4000331, 0x4000335, 0x4000339, 0x0, 0x400033D, 0x0, 0x4000341, 0x4000345, 0x6000349, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x400034F, 0x4000353, 0x4000357, 0x400035B, 0x400035F, 0x4000363, 0x6000367, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000349, 0x4000367, 0x400036D, 0x4000371, 0x4000375, 0x0, 0x2001D89, 0x2001D8B, 0x2000341, 0x4000341, 0x4000353, 0x2001D8D, 0x2001D8F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2001D91, 0x2000E17, 0x2001D93, 0x0, 0x2001D95, 0x200035B, 0x0, 0x0, 0x0, 0x2001D97, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000381, 0x4000385, 0x0, 0x4000389, 0x0, 0x0, 0x0, 0x400038D, 0x0, 0x0, 0x0, 0x0, 0x4000391, 0x4000395, 0x4000399, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x400039D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40003A1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40003A5, 0x40003A9, 0x0, 0x40003AD, 0x0, 0x0, 0x0, 0x40003B1, 0x0, 0x0, 0x0, 0x0, 0x40003B5, 0x40003B9, 0x40003BD, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40003C1, 0x40003C5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40003C9, 0x40003CD, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40003D1, 0x40003D5, 0x40003D9, 0x40003DD, 0x0, 0x0, 0x40003E1, 0x40003E5, 0x0, 0x0, 0x40003E9, 0x40003ED, 0x40003F1, 0x40003F5, 0x40003F9, 0x40003FD, 0x0, 0x0, 0x4000401, 0x4000405, 0x4000409, 0x400040D, 0x4000411, 0x4000415, 0x0, 0x0, 0x4000419, 0x400041D, 0x4000421, 0x4000425, 0x4000429, 0x400042D, 0x4000431, 0x4000435, 0x4000439, 0x400043D, 0x4000441, 0x4000445, 0x0, 0x0, 0x4000449, 0x400044D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4001D99, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000451, 0x4000455, 0x4000459, 0x400045D, 0x4000461, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4001D9D, 0x4001DA1, 0x4001DA5, 0x4001DA9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000465, 0x0, 0x4000469, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x400046D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000471, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000477, 0x0, 0x0, 0x600047D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000483, 0x6000489, 0x600048F, 0x6000495, 0x600049B, 0x60004A1, 0x60004A7, 0x60004AD, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60004B3, 0x60004B9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60004BF, 0x60004C5, 0x0, 0x60004CB, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60004D1, 0x0, 0x0, 0x60004D7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60004DD, 0x60004E3, 0x60004E9, 0x0, 0x0, 0x60004EF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60004F5, 0x0, 0x0, 0x60004FB, 0x6000501, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000507, 0x600050D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000513, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000519, 0x600051F, 0x6000525, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x600052B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000531, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000537, 0x600053D, 0x0, 0x6000543, 0x9001DAD, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000552, 0x6000558, 0x600055E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000564, 0x0, 0x600056A, 0x9001DB6, 0x6000579, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6001DBF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6001DC5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6001DCB, 0x6001DD1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3001DD7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x600057F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000585, 0x0, 0x0, 0x0, 0x0, 0x600058B, 0x0, 0x0, 0x0, 0x0, 0x6000591, 0x0, 0x0, 0x0, 0x0, 0x6000597, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x600059D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60005A3, 0x0, 0x60005A9, 0x60005AF, 0x9001DDA, 0x60005B5, 0x9001DE3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60005BB, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60005C1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60005C7, 0x0, 0x0, 0x0, 0x0, 0x60005CD, 0x0, 0x0, 0x0, 0x0, 0x60005D3, 0x0, 0x0, 0x0, 0x0, 0x60005D9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60005DF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60005E5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3001DEC, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60005EB, 0x0, 0x60005F1, 0x0, 0x60005F7, 0x0, 0x60005FD, 0x0, 0x6000603, 0x0, 0x0, 0x0, 0x6000609, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x600060F, 0x0, 0x6000615, 0x0, 0x0, 0x600061B, 0x6000621, 0x0, 0x6000627, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000000, 0x2000243, 0x1000633, 0x0, 0x10000C9, 0x1000015, 0x2001DEF, 0x10000ED, 0x1000105, 0x1000021, 0x1000126, 0x100012C, 0x1000132, 0x10006FF, 0x100002D, 0x0, 0x1000030, 0x2001DF1, 0x1000751, 0x1000168, 0x1000192, 0x100003F, 0x10001C2, 0x100004E, 0x2001DF3, 0x2001DF5, 0x3001DF7, 0x1000636, 0x10000CC, 0x1000063, 0x2001DFA, 0x2001DFC, 0x2001DFE, 0x10000F0, 0x0, 0x100012F, 0x1000702, 0x2001E00, 0x100007E, 0x2001E02, 0x3001E04, 0x3001E07, 0x1000754, 0x1000195, 0x100008D, 0x3001E0A, 0x2001E0D, 0x10007E4, 0x3001E0F, 0x2001D89, 0x2001E12, 0x2001E14, 0x2001D8D, 0x2001E16, 0x100006F, 0x100016B, 0x100008D, 0x10007E4, 0x2001D89, 0x2001E12, 0x2000E17, 0x2001D8D, 0x2001E16, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2001E18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2001E1A, 0x1000060, 0x2001E1C, 0x2001E1E, 0x2001DFE, 0x100069A, 0x2001E20, 0x2001E22, 0x2001E24, 0x2001E26, 0x2001E28, 0x2001E2A, 0x3001E2C, 0x2001E2F, 0x2001E31, 0x3001E33, 0x2001E36, 0x2001E38, 0x2001E3A, 0x2001E3C, 0x2001E3E, 0x2001E40, 0x2001E42, 0x2001E44, 0x2001E46, 0x2001E48, 0x2001E4A, 0x2001E4C, 0x2001E4E, 0x3001E50, 0x2001E53, 0x2001E55, 0x10001D4, 0x2001E57, 0x2001E59, 0x200026B, 0x2001D8B, 0x300062D, 0x3000630, 0x3000633, 0x3000636, 0x3000639, 0x300063C, 0x300063F, 0x3000642, 0x5000645, 0x500064A, 0x300064F, 0x3000652, 0x3000655, 0x3000658, 0x300065B, 0x300065E, 0x3000661, 0x3000664, 0x3000667, 0x300066A, 0x500066D, 0x5000672, 0x5000677, 0x500067C, 0x3000681, 0x3000684, 0x3000687, 0x300068A, 0x500068D, 0x5000692, 0x3000697, 0x300069A, 0x300069D, 0x30006A0, 0x30006A3, 0x30006A6, 0x30006A9, 0x30006AC, 0x30006AF, 0x30006B2, 0x30006B5, 0x30006B8, 0x30006BB, 0x30006BE, 0x30006C1, 0x30006C4, 0x50006C7, 0x50006CC, 0x30006D1, 0x30006D4, 0x30006D7, 0x30006DA, 0x30006DD, 0x30006E0, 0x30006E3, 0x30006E6, 0x50006E9, 0x50006EE, 0x30006F3, 0x30006F6, 0x30006F9, 0x30006FC, 0x30006FF, 0x3000702, 0x3000705, 0x3000708, 0x300070B, 0x300070E, 0x3000711, 0x3000714, 0x3000717, 0x300071A, 0x300071D, 0x3000720, 0x3000723, 0x3000726, 0x5000729, 0x500072E, 0x5000733, 0x5000738, 0x500073D, 0x5000742, 0x5000747, 0x500074C, 0x3000751, 0x3000754, 0x3000757, 0x300075A, 0x300075D, 0x3000760, 0x3000763, 0x3000766, 0x5000769, 0x500076E, 0x3000773, 0x3000776, 0x3000779, 0x300077C, 0x300077F, 0x3000782, 0x5000785, 0x500078A, 0x500078F, 0x5000794, 0x5000799, 0x500079E, 0x30007A3, 0x30007A6, 0x30007A9, 0x30007AC, 0x30007AF, 0x30007B2, 0x30007B5, 0x30007B8, 0x30007BB, 0x30007BE, 0x30007C1, 0x30007C4, 0x30007C7, 0x30007CA, 0x50007CD, 0x50007D2, 0x50007D7, 0x50007DC, 0x30007E1, 0x30007E4, 0x30007E7, 0x30007EA, 0x30007ED, 0x30007F0, 0x30007F3, 0x30007F6, 0x30007F9, 0x30007FC, 0x30007FF, 0x3000802, 0x3000805, 0x3000808, 0x300080B, 0x300080E, 0x3000811, 0x3000814, 0x3000817, 0x300081A, 0x300081D, 0x3000820, 0x3000823, 0x3000826, 0x3000829, 0x300082C, 0x300082F, 0x3000832, 0x3000835, 0x3000838, 0x3001E5B, 0x300077C, 0x0, 0x0, 0x0, 0x0, 0x300083F, 0x3000842, 0x3000845, 0x3000848, 0x500084B, 0x5000850, 0x5000855, 0x500085A, 0x500085F, 0x5000864, 0x5000869, 0x500086E, 0x5000873, 0x5000878, 0x500087D, 0x5000882, 0x5000887, 0x500088C, 0x5000891, 0x5000896, 0x500089B, 0x50008A0, 0x50008A5, 0x50008AA, 0x30008AF, 0x30008B2, 0x30008B5, 0x30008B8, 0x30008BB, 0x30008BE, 0x50008C1, 0x50008C6, 0x50008CB, 0x50008D0, 0x50008D5, 0x50008DA, 0x50008DF, 0x50008E4, 0x50008E9, 0x50008EE, 0x30008F3, 0x30008F6, 0x30008F9, 0x30008FC, 0x30008FF, 0x3000902, 0x3000905, 0x3000908, 0x500090B, 0x5000910, 0x5000915, 0x500091A, 0x500091F, 0x5000924, 0x5000929, 0x500092E, 0x5000933, 0x5000938, 0x500093D, 0x5000942, 0x5000947, 0x500094C, 0x5000951, 0x5000956, 0x500095B, 0x5000960, 0x5000965, 0x500096A, 0x300096F, 0x3000972, 0x3000975, 0x3000978, 0x500097B, 0x5000980, 0x5000985, 0x500098A, 0x500098F, 0x5000994, 0x5000999, 0x500099E, 0x50009A3, 0x50009A8, 0x30009AD, 0x30009B0, 0x30009B3, 0x30009B6, 0x30009B9, 0x30009BC, 0x30009BF, 0x30009C2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40009C5, 0x40009C9, 0x60009CD, 0x60009D3, 0x60009D9, 0x60009DF, 0x60009E5, 0x60009EB, 0x40009F1, 0x40009F5, 0x60009F9, 0x60009FF, 0x6000A05, 0x6000A0B, 0x6000A11, 0x6000A17, 0x4000A1D, 0x4000A21, 0x6000A25, 0x6000A2B, 0x6000A31, 0x6000A37, 0x0, 0x0, 0x4000A3D, 0x4000A41, 0x6000A45, 0x6000A4B, 0x6000A51, 0x6000A57, 0x0, 0x0, 0x4000A5D, 0x4000A61, 0x6000A65, 0x6000A6B, 0x6000A71, 0x6000A77, 0x6000A7D, 0x6000A83, 0x4000A89, 0x4000A8D, 0x6000A91, 0x6000A97, 0x6000A9D, 0x6000AA3, 0x6000AA9, 0x6000AAF, 0x4000AB5, 0x4000AB9, 0x6000ABD, 0x6000AC3, 0x6000AC9, 0x6000ACF, 0x6000AD5, 0x6000ADB, 0x4000AE1, 0x4000AE5, 0x6000AE9, 0x6000AEF, 0x6000AF5, 0x6000AFB, 0x6000B01, 0x6000B07, 0x4000B0D, 0x4000B11, 0x6000B15, 0x6000B1B, 0x6000B21, 0x6000B27, 0x0, 0x0, 0x4000B2D, 0x4000B31, 0x6000B35, 0x6000B3B, 0x6000B41, 0x6000B47, 0x0, 0x0, 0x4000B4D, 0x4000B51, 0x6000B55, 0x6000B5B, 0x6000B61, 0x6000B67, 0x6000B6D, 0x6000B73, 0x0, 0x4000B79, 0x0, 0x6001E5E, 0x0, 0x6000B83, 0x0, 0x6000B89, 0x4000B8F, 0x4000B93, 0x6000B97, 0x6000B9D, 0x6000BA3, 0x6000BA9, 0x6000BAF, 0x6000BB5, 0x4000BBB, 0x4000BBF, 0x6000BC3, 0x6000BC9, 0x6000BCF, 0x6000BD5, 0x6000BDB, 0x6000BE1, 0x4000BE7, 0x4000357, 0x4000BEB, 0x400035B, 0x4000BEF, 0x400035F, 0x4000BF3, 0x4000363, 0x4000BF7, 0x400036D, 0x4000BFB, 0x4000371, 0x4000BFF, 0x4000375, 0x0, 0x0, 0x6000C03, 0x6000C09, 0x8000C0F, 0x8000C17, 0x8000C1F, 0x8000C27, 0x8000C2F, 0x8000C37, 0x6000C3F, 0x6000C45, 0x8000C4B, 0x8000C53, 0x8000C5B, 0x8000C63, 0x8000C6B, 0x8000C73, 0x6000C7B, 0x6000C81, 0x8000C87, 0x8000C8F, 0x8000C97, 0x8000C9F, 0x8000CA7, 0x8000CAF, 0x6000CB7, 0x6000CBD, 0x8000CC3, 0x8000CCB, 0x8000CD3, 0x8000CDB, 0x8000CE3, 0x8000CEB, 0x6000CF3, 0x6000CF9, 0x8000CFF, 0x8000D07, 0x8000D0F, 0x8000D17, 0x8000D1F, 0x8000D27, 0x6000D2F, 0x6000D35, 0x8000D3B, 0x8000D43, 0x8000D4B, 0x8000D53, 0x8000D5B, 0x8000D63, 0x4000D6B, 0x4000D6F, 0x6000D73, 0x4000D79, 0x6000D7D, 0x0, 0x4000D83, 0x6001E64, 0x4000D8D, 0x4000D91, 0x4000D95, 0x400032B, 0x4000D99, 0x3001E6A, 0x2000349, 0x3001E6A, 0x3001E6D, 0x5001E70, 0x6000DA1, 0x4000DA7, 0x6000DAB, 0x0, 0x4000DB1, 0x6001E75, 0x4000DBB, 0x4000331, 0x4000DBF, 0x4000335, 0x4000DC3, 0x5001E7B, 0x5001E80, 0x5001E85, 0x4000DD6, 0x4000DDA, 0x6000DDE, 0x6000349, 0x0, 0x0, 0x4000DE4, 0x6000DE8, 0x4000DEE, 0x4000DF2, 0x4000DF6, 0x4000339, 0x0, 0x5001E8A, 0x5001E8F, 0x5001E94, 0x4000E09, 0x4000E0D, 0x6000E11, 0x6000367, 0x4000E17, 0x4000E1B, 0x4000E1F, 0x6000E23, 0x4000E29, 0x4000E2D, 0x4000E31, 0x4000341, 0x4000E35, 0x5001E99, 0x5001D84, 0x1000E3D, 0x0, 0x0, 0x6000E3E, 0x4000E44, 0x6000E48, 0x0, 0x4000E4E, 0x6001E9E, 0x4000E58, 0x400033D, 0x4000E5C, 0x4000345, 0x4000E60, 0x3001D26, 0x3001E8A, 0x0, 0x1001D1D, 0x1001D1D, 0x1001D1D, 0x1001D1D, 0x1001D1D, 0x1001D1D, 0x1001D1D, 0x1001D1D, 0x1001D1D, 0x1001D1D, 0x1001D1D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3001EA4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3001EA7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1001EAA, 0x2001EAB, 0x3001EAA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1001D1D, 0x0, 0x0, 0x0, 0x6001EAD, 0x9001EB3, 0x0, 0x6001EBC, 0x9001EC2, 0x0, 0x0, 0x0, 0x0, 0x2001ECB, 0x0, 0x3001ECD, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2001ED0, 0x2001ED2, 0x2001ED4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xC001EAD, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1001D1D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1001ED6, 0x100006F, 0x0, 0x0, 0x1001D33, 0x1001ED7, 0x1001ED8, 0x1001ED9, 0x1001EDA, 0x1001EDB, 0x1001EDC, 0x3001EDD, 0x1000EB7, 0x1001EE0, 0x1001EE1, 0x100007B, 0x1001ED6, 0x1001D2E, 0x1001D24, 0x1001D25, 0x1001D33, 0x1001ED7, 0x1001ED8, 0x1001ED9, 0x1001EDA, 0x1001EDB, 0x1001EDC, 0x3001EDD, 0x1000EB7, 0x1001EE0, 0x1001EE1, 0x0, 0x100004E, 0x1000063, 0x100007E, 0x100080E, 0x2001DFA, 0x1000108, 0x100012F, 0x1000135, 0x1000702, 0x100007B, 0x1000754, 0x100017D, 0x1000195, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2001EE2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3001EE4, 0x3001EE7, 0x1000012, 0x3001EEA, 0x0, 0x3001EED, 0x3001EF0, 0x2001EF3, 0x0, 0x3001EF5, 0x10000F0, 0x1000105, 0x1000105, 0x1000105, 0x1000108, 0x2001EF8, 0x1000021, 0x1000021, 0x1000132, 0x1000135, 0x0, 0x100002D, 0x2001EFA, 0x0, 0x0, 0x1000751, 0x1001EFC, 0x1000168, 0x1000168, 0x1000168, 0x0, 0x0, 0x2001EFD, 0x3001EFF, 0x2001F02, 0x0, 0x10001D1, 0x0, 0x2000345, 0x0, 0x10001D1, 0x0, 0x100012C, 0x300000F, 0x1000633, 0x1000012, 0x0, 0x1000063, 0x1000015, 0x1000697, 0x0, 0x10006FF, 0x100007E, 0x20015C7, 0x20015D3, 0x20015D7, 0x20015DB, 0x100006F, 0x0, 0x3001F04, 0x2001D8F, 0x2001E12, 0x2001F07, 0x2001F09, 0x3001F0B, 0x0, 0x0, 0x0, 0x0, 0x10000C9, 0x10000CC, 0x1000063, 0x100006F, 0x1000129, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5001F0E, 0x5001F13, 0x6001F18, 0x5001F1E, 0x5001F23, 0x5001F28, 0x5001F2D, 0x5001F32, 0x5001F37, 0x5001F3C, 0x5001F41, 0x5001F46, 0x5001F4B, 0x5001F50, 0x5001F55, 0x4001D34, 0x1000021, 0x2001F5A, 0x3001F5C, 0x2001F5F, 0x10007E1, 0x2001F61, 0x3001F63, 0x4001F66, 0x2001F6A, 0x100080B, 0x2001F6C, 0x3001F6E, 0x1000132, 0x1000012, 0x10000C9, 0x10006FF, 0x100006F, 0x2001F71, 0x3001F73, 0x2001F76, 0x10007E4, 0x2001F78, 0x3001F7A, 0x4001F7D, 0x2001F81, 0x100080E, 0x2001F83, 0x3001F85, 0x1000135, 0x1000060, 0x10000CC, 0x1000702, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5001F88, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5000E6C, 0x5000E71, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5000E76, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5000E7B, 0x5000E80, 0x5000E85, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5000E8A, 0x0, 0x0, 0x0, 0x0, 0x5000E8F, 0x0, 0x0, 0x5000E94, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5000E99, 0x0, 0x5000E9E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6001F8D, 0x9001F93, 0x0, 0x6001F9C, 0x9001FA2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5000EA3, 0x0, 0x0, 0x5000EA8, 0x0, 0x0, 0x5000EAD, 0x0, 0x5000EB2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3000EB7, 0x0, 0x5000EBA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5000EBF, 0x3000EC4, 0x3000EC7, 0x5000ECA, 0x5000ECF, 0x0, 0x0, 0x5000ED4, 0x5000ED9, 0x0, 0x0, 0x5000EDE, 0x5000EE3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5000EE8, 0x5000EED, 0x0, 0x0, 0x5000EF2, 0x5000EF7, 0x0, 0x0, 0x5000EFC, 0x5000F01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5000F06, 0x5000F0B, 0x5000F10, 0x5000F15, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5000F1A, 0x5000F1F, 0x5000F24, 0x5000F29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5000F2E, 0x5000F33, 0x5000F38, 0x5000F3D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3000F42, 0x3000F45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1001D2E, 0x1001D24, 0x1001D25, 0x1001D33, 0x1001ED7, 0x1001ED8, 0x1001ED9, 0x1001EDA, 0x1001EDB, 0x2001F1C, 0x2001D2E, 0x2001FAB, 0x2001FAD, 0x2001FAF, 0x2001FB1, 0x2001FB3, 0x2001FB5, 0x2001FB7, 0x2001FB9, 0x2001FBB, 0x3001FBD, 0x3001FC0, 0x3001FC3, 0x3001FC6, 0x3001FC9, 0x3001FCC, 0x3001FCF, 0x3001FD2, 0x3001FD5, 0x4001FD8, 0x4001FDC, 0x4001FE0, 0x4001FE4, 0x4001FE8, 0x4001FEC, 0x4001FF0, 0x4001FF4, 0x4001FF8, 0x4001FFC, 0x4002000, 0x2002004, 0x2002006, 0x2002008, 0x200200A, 0x200200C, 0x200200E, 0x2002010, 0x2002012, 0x2002014, 0x3002016, 0x3002019, 0x300201C, 0x300201F, 0x3002022, 0x3002025, 0x3002028, 0x300202B, 0x300202E, 0x3002031, 0x3002034, 0x3002037, 0x300203A, 0x300203D, 0x3002040, 0x3002043, 0x3002046, 0x3002049, 0x300204C, 0x300204F, 0x3002052, 0x3002055, 0x3002058, 0x300205B, 0x300205E, 0x3002061, 0x3002064, 0x3002067, 0x300206A, 0x300206D, 0x3002070, 0x3002073, 0x3002076, 0x3002079, 0x300207C, 0x300207F, 0x3002082, 0x1000000, 0x1000633, 0x1000012, 0x10000C9, 0x1000015, 0x1000697, 0x10000ED, 0x1000105, 0x1000021, 0x1000126, 0x100012C, 0x1000132, 0x10006FF, 0x100002D, 0x1000030, 0x1000751, 0x1001EFC, 0x1000168, 0x100017A, 0x1000192, 0x100003F, 0x10007E1, 0x10001C2, 0x100080B, 0x100004B, 0x10001D1, 0x100004E, 0x1000636, 0x1000060, 0x10000CC, 0x1000063, 0x100069A, 0x10000F0, 0x1000108, 0x100006F, 0x1000129, 0x100012F, 0x1000135, 0x1000702, 0x100007B, 0x100007E, 0x1000754, 0x1002068, 0x100016B, 0x100017D, 0x1000195, 0x100008D, 0x10007E4, 0x10001C5, 0x100080E, 0x1000099, 0x10001D4, 0x1001ED6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xC001F8D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3002085, 0x2002088, 0x3002087, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5000F48, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000129, 0x10007E1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x300208A, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x300208D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3002090, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3002093, 0x3002096, 0x3002099, 0x300209C, 0x300209F, 0x30020A2, 0x30020A5, 0x30020A8, 0x30020AB, 0x30020AE, 0x30020B1, 0x30020B4, 0x30020B7, 0x30020BA, 0x30020BD, 0x30020C0, 0x300176F, 0x30020C3, 0x3001241, 0x30020C6, 0x30020C9, 0x30020CC, 0x30020CF, 0x30020D2, 0x30020D5, 0x30020D8, 0x30020DB, 0x30020DE, 0x30020E1, 0x30020E4, 0x30020E7, 0x30020EA, 0x30020ED, 0x30020F0, 0x30020F3, 0x30020F6, 0x30020F9, 0x3001226, 0x30020FC, 0x30020FF, 0x3002102, 0x3002105, 0x3001854, 0x3002108, 0x3001427, 0x300210B, 0x300210E, 0x3002111, 0x3002114, 0x3002117, 0x300211A, 0x300211D, 0x3002120, 0x3002123, 0x30018A3, 0x3002126, 0x3002129, 0x300212C, 0x300212F, 0x3002132, 0x3002135, 0x3002138, 0x300213B, 0x300213E, 0x3002141, 0x3002144, 0x3002147, 0x300214A, 0x300214D, 0x3002150, 0x3002153, 0x3002156, 0x3002159, 0x300215C, 0x300215F, 0x3002162, 0x3002165, 0x3001512, 0x3002168, 0x300216B, 0x300216E, 0x3002171, 0x3002174, 0x3002177, 0x300217A, 0x300217D, 0x3002180, 0x3002183, 0x3002186, 0x3002189, 0x300218C, 0x300218F, 0x3002192, 0x3002195, 0x3002198, 0x300219B, 0x300219E, 0x30021A1, 0x30021A4, 0x30021A7, 0x30021AA, 0x30021AD, 0x30021B0, 0x30021B3, 0x30021B6, 0x30021B9, 0x30021BC, 0x30021BF, 0x30021C2, 0x30021C5, 0x30021C8, 0x30021CB, 0x30021CE, 0x30021D1, 0x30021D4, 0x30021D7, 0x300137C, 0x30021DA, 0x30021DD, 0x30021E0, 0x30021E3, 0x30021E6, 0x30021E9, 0x30013E2, 0x3001142, 0x30021EC, 0x30021EF, 0x30021F2, 0x30021F5, 0x30021F8, 0x30021FB, 0x30021FE, 0x3002201, 0x3002204, 0x3002207, 0x300220A, 0x300220D, 0x3002210, 0x3002213, 0x3002216, 0x3002219, 0x300221C, 0x300221F, 0x30013AF, 0x3001C0A, 0x3002222, 0x30013B5, 0x3002225, 0x3002228, 0x300222B, 0x300222E, 0x3001C31, 0x3002231, 0x3002234, 0x3002237, 0x300223A, 0x300223D, 0x3002240, 0x30010AF, 0x3002243, 0x30011F6, 0x3002246, 0x3002249, 0x300224C, 0x300224F, 0x3001352, 0x30010C4, 0x3002252, 0x3002255, 0x3002258, 0x300225B, 0x300225E, 0x3002261, 0x3002264, 0x3002267, 0x300226A, 0x300226D, 0x3002270, 0x3002273, 0x3002276, 0x3002279, 0x300227C, 0x300227F, 0x3002282, 0x3002285, 0x3002288, 0x300228B, 0x300228E, 0x3002291, 0x3002294, 0x3002297, 0x300229A, 0x300229D, 0x30022A0, 0x30022A3, 0x30022A6, 0x30022A9, 0x3001166, 0x30022AC, 0x3001D01, 0x30022AF, 0x30022B2, 0x30022B5, 0x3001D07, 0x30022B8, 0x30022BB, 0x30022BE, 0x30022C1, 0x3001D16, 0x30022C4, 0x30022C7, 0x30012E6, 0x30010BE, 0x30022CA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1001D1D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30022CD, 0x0, 0x30020D2, 0x30022D0, 0x30022D3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000F4D, 0x0, 0x6000F53, 0x0, 0x6000F59, 0x0, 0x6000F5F, 0x0, 0x6000F65, 0x0, 0x6000F6B, 0x0, 0x6000F71, 0x0, 0x6000F77, 0x0, 0x6000F7D, 0x0, 0x6000F83, 0x0, 0x6000F89, 0x0, 0x6000F8F, 0x0, 0x0, 0x6000F95, 0x0, 0x6000F9B, 0x0, 0x6000FA1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000FA7, 0x6000FAD, 0x0, 0x6000FB3, 0x6000FB9, 0x0, 0x6000FBF, 0x6000FC5, 0x0, 0x6000FCB, 0x6000FD1, 0x0, 0x6000FD7, 0x6000FDD, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000FE3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40022D6, 0x40022DA, 0x0, 0x6000FE9, 0x60022DE, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000FEF, 0x0, 0x6000FF5, 0x0, 0x6000FFB, 0x0, 0x6001001, 0x0, 0x6001007, 0x0, 0x600100D, 0x0, 0x6001013, 0x0, 0x6001019, 0x0, 0x600101F, 0x0, 0x6001025, 0x0, 0x600102B, 0x0, 0x6001031, 0x0, 0x0, 0x6001037, 0x0, 0x600103D, 0x0, 0x6001043, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6001049, 0x600104F, 0x0, 0x6001055, 0x600105B, 0x0, 0x6001061, 0x6001067, 0x0, 0x600106D, 0x6001073, 0x0, 0x6001079, 0x600107F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6001085, 0x0, 0x0, 0x600108B, 0x6001091, 0x6001097, 0x600109D, 0x0, 0x0, 0x0, 0x60010A3, 0x60022E4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30022EA, 0x30022ED, 0x30022F0, 0x30022F3, 0x30022F6, 0x30022F9, 0x30022FC, 0x30022FF, 0x3002302, 0x3002305, 0x3002308, 0x300230B, 0x300230E, 0x3002311, 0x3002314, 0x3002317, 0x300231A, 0x300231D, 0x3002320, 0x3002323, 0x3002326, 0x3002329, 0x300232C, 0x300232F, 0x3002332, 0x3002335, 0x3002338, 0x300233B, 0x300233E, 0x3002341, 0x3002344, 0x3002347, 0x300234A, 0x300234D, 0x3002350, 0x3002353, 0x3002356, 0x3002359, 0x300235C, 0x300235F, 0x3002362, 0x3002365, 0x3002368, 0x300236B, 0x300236E, 0x3002371, 0x3002374, 0x3002377, 0x300237A, 0x300237D, 0x3002380, 0x3002383, 0x3002386, 0x3002389, 0x300238C, 0x300238F, 0x3002392, 0x3002395, 0x3002398, 0x300239B, 0x300239E, 0x30023A1, 0x30023A4, 0x30023A7, 0x30023AA, 0x30023AD, 0x30023B0, 0x30023B3, 0x30023B6, 0x30023B9, 0x30023BC, 0x30023BF, 0x30023C2, 0x30023C5, 0x30023C8, 0x30023CB, 0x30023CE, 0x30023D1, 0x30023D4, 0x30023D7, 0x30023DA, 0x30023DD, 0x30023E0, 0x30023E3, 0x30023E6, 0x30023E9, 0x30023EC, 0x30023EF, 0x30023F2, 0x30023F5, 0x30023F8, 0x30023FB, 0x30023FE, 0x3002401, 0x0, 0x0, 0x0, 0x3002093, 0x30020A5, 0x3002404, 0x3002407, 0x300240A, 0x300240D, 0x3002410, 0x3002413, 0x300209F, 0x3002416, 0x3002419, 0x300241C, 0x300241F, 0x30020AB, 0x5002422, 0x5002427, 0x500242C, 0x5002431, 0x5002436, 0x500243B, 0x5002440, 0x5002445, 0x500244A, 0x500244F, 0x5002454, 0x5002459, 0x500245E, 0x5002463, 0x8002468, 0x8002470, 0x8002478, 0x8002480, 0x8002488, 0x8002490, 0x8002498, 0x80024A0, 0x80024A8, 0x80024B0, 0x80024B8, 0x80024C0, 0x80024C8, 0x80024D0, 0x80024D8, 0x110024E0, 0xE0024F1, 0x0, 0x50024FF, 0x5002504, 0x5002509, 0x500250E, 0x5002513, 0x5002518, 0x500251D, 0x5002522, 0x5002527, 0x500252C, 0x5002531, 0x5002536, 0x500253B, 0x5002540, 0x5002545, 0x500254A, 0x500254F, 0x5002554, 0x5002559, 0x500255E, 0x5002563, 0x5002568, 0x500256D, 0x5002572, 0x5002577, 0x500257C, 0x5002581, 0x5002586, 0x500258B, 0x5002590, 0x5002595, 0x500259A, 0x500259F, 0x50025A4, 0x50025A9, 0x50025AE, 0x30025B3, 0x30025B6, 0x3002147, 0x30025B9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30025BC, 0x2001FAC, 0x20025BF, 0x2001D24, 0x20025C1, 0x20025C3, 0x20025C5, 0x20025C7, 0x20025C9, 0x20025CB, 0x20025CD, 0x2001F27, 0x2001F22, 0x20025CF, 0x20025D1, 0x20025D3, 0x30022EA, 0x30022F3, 0x30022FC, 0x3002302, 0x300231A, 0x300231D, 0x3002326, 0x300232C, 0x300232F, 0x3002335, 0x3002338, 0x300233B, 0x300233E, 0x3002341, 0x6002469, 0x6002471, 0x6002479, 0x6002481, 0x6002489, 0x6002491, 0x6002499, 0x60024A1, 0x60024A9, 0x60024B1, 0x60024B9, 0x60024C1, 0x60024C9, 0x6002341, 0xF0025D5, 0xC0025E4, 0x60025F0, 0x0, 0x3002093, 0x30020A5, 0x3002404, 0x3002407, 0x3002514, 0x300130D, 0x300251E, 0x30020B4, 0x3002528, 0x30020D2, 0x300215C, 0x300217D, 0x300217A, 0x300215F, 0x30010C4, 0x30020EA, 0x3002156, 0x3002555, 0x300255A, 0x3001457, 0x3002564, 0x3002569, 0x300256E, 0x3001466, 0x3002578, 0x30025F6, 0x30025F9, 0x3001226, 0x30025FC, 0x30025FF, 0x3002602, 0x3002605, 0x3002608, 0x30025A5, 0x300260B, 0x300260E, 0x300240A, 0x300240D, 0x3002410, 0x3002611, 0x3002614, 0x3002617, 0x300261A, 0x3002587, 0x300258C, 0x3002591, 0x3002596, 0x300259B, 0x300261D, 0x2002620, 0x2002622, 0x2002624, 0x2002626, 0x2002628, 0x2001D33, 0x20025C2, 0x20025D2, 0x200262A, 0x200262C, 0x200262E, 0x2002630, 0x2002632, 0x2002634, 0x2002636, 0x4002638, 0x400263C, 0x4002640, 0x4002644, 0x4002648, 0x400264C, 0x4002650, 0x4002654, 0x4002658, 0x500265C, 0x5002661, 0x5002666, 0x200266B, 0x300266D, 0x2002670, 0x3002672, 0x3002675, 0x3002678, 0x3001085, 0x300267B, 0x300267E, 0x3000FEF, 0x3000FF5, 0x3000FFB, 0x3001001, 0x3001007, 0x300100D, 0x3001013, 0x3001019, 0x300101F, 0x3001025, 0x300102B, 0x3001031, 0x3001037, 0x300103D, 0x3001043, 0x3002681, 0x3002684, 0x3002687, 0x300268A, 0x300268D, 0x3001049, 0x3001055, 0x3001061, 0x300106D, 0x3001079, 0x3002690, 0x3002693, 0x3002696, 0x3002699, 0x300269C, 0x300269F, 0x30026A2, 0x30026A5, 0x30026A8, 0x30026AB, 0x30026AE, 0x30026B1, 0x30026B4, 0x300108B, 0x3001091, 0x3001097, 0x300109D, 0x0, 0xF0026B7, 0xC0026C6, 0xF0026D2, 0x90026E1, 0xF0026EA, 0x90026F9, 0x9002702, 0x1200270B, 0xC00271D, 0x9002729, 0x9002732, 0x900273B, 0xC002744, 0xC002750, 0xC00275C, 0xC002768, 0xC002774, 0xC002780, 0xC00278C, 0x12002798, 0x60027AA, 0x120027B0, 0x120027C2, 0xF0027D4, 0xC0027B6, 0x120027E3, 0x120027F5, 0xC002807, 0x9002813, 0x900281C, 0xC002825, 0xC002831, 0xF00283D, 0xF00284C, 0x900285B, 0x9002864, 0xC00286D, 0x9002879, 0x9002882, 0x60027EF, 0x600288B, 0x9002891, 0x900289A, 0x120028A3, 0xC0028B5, 0xF0028C1, 0x120028D0, 0xC0028E2, 0x90028EE, 0x90028F7, 0x12002900, 0xC002912, 0x1200291E, 0x9002930, 0xF002939, 0x9002948, 0xC002951, 0x900295D, 0xC002966, 0xF002972, 0xC002981, 0xF00298D, 0xC00299C, 0x60029A8, 0xF0029AE, 0x90029BD, 0x90029C6, 0xC0029CF, 0x90029DB, 0x90029E4, 0x90029ED, 0xF0029F6, 0xC002A05, 0x6002A11, 0x12002A17, 0x9002A29, 0xF002A32, 0xC0027C8, 0xC002A41, 0x9002A4D, 0x9002A56, 0xC002A5F, 0x6002A6B, 0xC002A71, 0xF002A7D, 0x6002A8C, 0x12002A92, 0x90027DA, 0x4002AA4, 0x4002AA8, 0x4002AAC, 0x4002AB0, 0x4002AB4, 0x4002AB8, 0x4002ABC, 0x4002AC0, 0x4002AC4, 0x4002AC8, 0x5002ACC, 0x5002AD1, 0x5002AD6, 0x5002ADB, 0x5002AE0, 0x5002AE5, 0x5002AEA, 0x5002AEF, 0x5002AF4, 0x5002AF9, 0x5002AFE, 0x5002B03, 0x5002B08, 0x5002B0D, 0x5002B12, 0x3002B17, 0x2002B1A, 0x2002B1C, 0x3002B1E, 0x2002B21, 0x2002B23, 0x2002B25, 0x3002B27, 0x3002B2A, 0x2002B2D, 0x6002B2F, 0x6002B35, 0x6002B3B, 0x6002B41, 0xC002B47, 0x2002B53, 0x2002B55, 0x3002B57, 0x2002B5A, 0x2002B5C, 0x2002B5E, 0x2002B60, 0x2002B62, 0x3002B64, 0x4002B67, 0x2002B6B, 0x2002B6D, 0x3002B6F, 0x3002B72, 0x2002B75, 0x2002B77, 0x2002B79, 0x3002B7B, 0x3002B7E, 0x3002B81, 0x3002B84, 0x3002B87, 0x2002B8A, 0x2002B8C, 0x2002B8E, 0x2002B90, 0x2002B92, 0x3002B94, 0x2002B97, 0x2002B99, 0x2002B9B, 0x3002B9D, 0x3002BA0, 0x2002B28, 0x3002BA3, 0x3002BA6, 0x3002BA9, 0x2002B2B, 0x3002BAC, 0x5002BAF, 0x6002BB4, 0x2002B18, 0x3002BBA, 0x3002BBD, 0x3002BC0, 0x3002BC3, 0x7002BC6, 0x8002BCD, 0x2002BD5, 0x2002BD7, 0x3002BD9, 0x2002BDC, 0x2002BDE, 0x2002BE0, 0x3002BE2, 0x2002BE5, 0x2002BE7, 0x2002BE9, 0x2002BEB, 0x2002BED, 0x3002BEF, 0x2002BF2, 0x2002BF4, 0x2002BF6, 0x3002BF8, 0x3002BFB, 0x4002BFE, 0x2002C02, 0x2002C04, 0x2002B24, 0x6002C06, 0x3002C0C, 0x2002C0F, 0x2002C11, 0x2002C13, 0x2002C15, 0x2002C17, 0x2002C19, 0x2002C1B, 0x2002C1D, 0x2002B89, 0x2002C1F, 0x3002C21, 0x2002C24, 0x2002C26, 0x3002C28, 0x3002C2B, 0x2002C2E, 0x4002C30, 0x3002C34, 0x2002C37, 0x2002BCC, 0x2002C39, 0x2002C3B, 0x5002C3D, 0x5002C42, 0x4002C47, 0x4002C4B, 0x4002C4F, 0x4002C53, 0x4002C57, 0x4002C5B, 0x4002C5F, 0x4002C63, 0x4002C67, 0x5002C6B, 0x5002C70, 0x5002C75, 0x5002C7A, 0x5002C7F, 0x5002C84, 0x5002C89, 0x5002C8E, 0x5002C93, 0x5002C98, 0x5002C9D, 0x5002CA2, 0x5002CA7, 0x5002CAC, 0x5002CB1, 0x5002CB6, 0x5002CBB, 0x5002CC0, 0x5002CC5, 0x5002CCA, 0x5002CCF, 0x5002CD4, 0x3002CD9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2002CDC, 0x2002CDE, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3002CE0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2002CE3, 0x2002CE5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3002CE7, 0x3002CEA, 0x2002CED, 0x3002CEF, 0x30010A9, 0x30010AC, 0x30010AF, 0x30010B2, 0x30010B5, 0x30010B8, 0x30010BB, 0x30010BE, 0x30010BE, 0x30010C1, 0x30010C4, 0x30010C7, 0x30010CA, 0x30010CD, 0x30010D0, 0x30010D3, 0x30010D6, 0x30010D9, 0x30010DC, 0x30010DF, 0x30010E2, 0x30010E5, 0x30010E8, 0x30010EB, 0x30010EE, 0x30010F1, 0x30010F4, 0x30010F7, 0x30010FA, 0x30010FD, 0x3001100, 0x3001103, 0x3001106, 0x3001109, 0x300110C, 0x300110F, 0x3001112, 0x3001115, 0x3001118, 0x300111B, 0x300111E, 0x3001121, 0x3001124, 0x3001127, 0x300112A, 0x300112D, 0x3001130, 0x3001133, 0x3001136, 0x3001139, 0x300113C, 0x300113F, 0x3001142, 0x3001145, 0x3001148, 0x300114B, 0x300114E, 0x3001151, 0x3001154, 0x3001157, 0x300115A, 0x300115D, 0x3001160, 0x3001163, 0x3001166, 0x3001169, 0x300116C, 0x300116F, 0x3001172, 0x3001175, 0x3001178, 0x300117B, 0x300117E, 0x3001181, 0x3001184, 0x3001187, 0x300118A, 0x300118D, 0x3001190, 0x3001193, 0x3001196, 0x3001199, 0x300119C, 0x300119F, 0x30011A2, 0x30011A5, 0x30011A8, 0x30011AB, 0x30011AE, 0x30011B1, 0x30011B4, 0x30011B7, 0x30010E2, 0x30011BA, 0x30011BD, 0x30011C0, 0x30011C3, 0x30011C6, 0x30011C9, 0x30011CC, 0x30011CF, 0x30011D2, 0x30011D5, 0x30011D8, 0x30011DB, 0x30011DE, 0x30011E1, 0x30011E4, 0x30011E7, 0x30011EA, 0x30011ED, 0x30011F0, 0x30011F3, 0x30011F6, 0x30011F9, 0x30011FC, 0x30011FF, 0x3001202, 0x3001205, 0x3001208, 0x300120B, 0x300120E, 0x3001211, 0x3001214, 0x3001217, 0x300121A, 0x300121D, 0x3001220, 0x3001223, 0x3001226, 0x3001229, 0x300122C, 0x300122F, 0x3001232, 0x3001235, 0x3001238, 0x300123B, 0x300123E, 0x3001241, 0x3001244, 0x3001247, 0x300124A, 0x300124D, 0x3001250, 0x3001253, 0x3001256, 0x3001259, 0x300125C, 0x300125F, 0x3001262, 0x3001265, 0x3001268, 0x300126B, 0x300126E, 0x3001271, 0x3001274, 0x3001277, 0x300127A, 0x300127D, 0x3001280, 0x3001283, 0x30011F0, 0x3001286, 0x3001289, 0x300128C, 0x300128F, 0x3001292, 0x3001295, 0x3001298, 0x300129B, 0x30011C0, 0x300129E, 0x30012A1, 0x30012A4, 0x30012A7, 0x30012AA, 0x30012AD, 0x30012B0, 0x30012B3, 0x30012B6, 0x30012B9, 0x30012BC, 0x30012BF, 0x30012C2, 0x30012C5, 0x30012C8, 0x30012CB, 0x30012CE, 0x30012D1, 0x30012D4, 0x30012D7, 0x30010E2, 0x30012DA, 0x30012DD, 0x30012E0, 0x30012E3, 0x30012E6, 0x30012E9, 0x30012EC, 0x30012EF, 0x30012F2, 0x30012F5, 0x30012F8, 0x30012FB, 0x30012FE, 0x3001301, 0x3001304, 0x3001307, 0x300130A, 0x300130D, 0x3001310, 0x3001313, 0x3001316, 0x3001319, 0x300131C, 0x300131F, 0x3001322, 0x3001325, 0x3001328, 0x30011C6, 0x300132B, 0x300132E, 0x3001331, 0x3001334, 0x3001337, 0x300133A, 0x300133D, 0x3001340, 0x3001343, 0x3001346, 0x3001349, 0x300134C, 0x300134F, 0x3001352, 0x3001355, 0x3001358, 0x300135B, 0x300135E, 0x3001361, 0x3001364, 0x3001367, 0x300136A, 0x300136D, 0x3001370, 0x3001373, 0x3001376, 0x3001379, 0x300137C, 0x300137F, 0x3001382, 0x3001385, 0x3001388, 0x300138B, 0x300138E, 0x3001391, 0x3001394, 0x3001397, 0x300139A, 0x300139D, 0x30013A0, 0x30013A3, 0x30013A6, 0x30013A9, 0x30013AC, 0x30013AF, 0x30013B2, 0x30013B5, 0x30013B8, 0x30013BB, 0x30013BE, 0x0, 0x0, 0x30013C1, 0x0, 0x30013C4, 0x0, 0x0, 0x30013C7, 0x30013CA, 0x30013CD, 0x30013D0, 0x30013D3, 0x30013D6, 0x30013D9, 0x30013DC, 0x30013DF, 0x30013E2, 0x0, 0x30013E5, 0x0, 0x30013E8, 0x0, 0x0, 0x30013EB, 0x30013EE, 0x0, 0x0, 0x0, 0x30013F1, 0x30013F4, 0x30013F7, 0x30013FA, 0x30013FD, 0x3001400, 0x3001403, 0x3001406, 0x3001409, 0x300140C, 0x300140F, 0x3001412, 0x3001415, 0x3001418, 0x300141B, 0x300141E, 0x3001421, 0x3001424, 0x3001427, 0x300142A, 0x300142D, 0x3001430, 0x3001433, 0x3001436, 0x3001439, 0x300143C, 0x300143F, 0x3001442, 0x3001445, 0x3001448, 0x300144B, 0x300144E, 0x3001451, 0x3001454, 0x3001457, 0x300145A, 0x300145D, 0x3001460, 0x3001463, 0x3001466, 0x3001469, 0x300146C, 0x300146F, 0x3001472, 0x3001475, 0x3001265, 0x3001478, 0x300147B, 0x300147E, 0x3001481, 0x3001484, 0x3001487, 0x3001487, 0x300148A, 0x300148D, 0x3001490, 0x3001493, 0x3001496, 0x3001499, 0x300149C, 0x300149F, 0x30013EB, 0x30014A2, 0x30014A5, 0x30014A8, 0x30014AB, 0x40014AE, 0x30014B2, 0x0, 0x0, 0x30014B5, 0x30014B8, 0x30014BB, 0x30014BE, 0x30014C1, 0x30014C4, 0x30014C7, 0x30014CA, 0x3001415, 0x30014CD, 0x30014D0, 0x30014D3, 0x30013C1, 0x30014D6, 0x30014D9, 0x30014DC, 0x30014DF, 0x30014E2, 0x30014E5, 0x30014E8, 0x30014EB, 0x30014EE, 0x30014F1, 0x30014F4, 0x30014F7, 0x3001430, 0x30014FA, 0x3001433, 0x30014FD, 0x3001500, 0x3001503, 0x3001506, 0x3001509, 0x30013C4, 0x3001121, 0x300150C, 0x300150F, 0x3001512, 0x30011F3, 0x30012F8, 0x3001515, 0x3001518, 0x3001448, 0x300151B, 0x300144B, 0x300151E, 0x3001521, 0x3001524, 0x30013CA, 0x3001527, 0x300152A, 0x300152D, 0x3001530, 0x3001533, 0x30013CD, 0x3001536, 0x3001539, 0x300153C, 0x300153F, 0x3001542, 0x3001545, 0x3001475, 0x3001548, 0x300154B, 0x3001265, 0x300154E, 0x3001481, 0x3001551, 0x3001554, 0x3001557, 0x300155A, 0x300155D, 0x3001490, 0x3001560, 0x30013E8, 0x3001563, 0x3001493, 0x30011BA, 0x3001566, 0x3001496, 0x3001569, 0x300149C, 0x300156C, 0x300156F, 0x3001572, 0x3001575, 0x3001578, 0x30014A2, 0x30013DC, 0x300157B, 0x30014A5, 0x300157E, 0x30014A8, 0x3001581, 0x30010BE, 0x4001584, 0x4001588, 0x400158C, 0x3001590, 0x3001593, 0x3001596, 0x4001599, 0x400159D, 0x40015A1, 0x30015A5, 0x30015A8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2002CF2, 0x2002CF4, 0x2002CF6, 0x3002CF8, 0x3002CFB, 0x2002CFE, 0x2002CFE, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4002D00, 0x4002D04, 0x4002D08, 0x4002D0C, 0x4002D10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40015AB, 0x0, 0x40015AF, 0x2002D14, 0x20015C7, 0x20015DB, 0x20015DF, 0x20015F7, 0x20015FB, 0x2002D16, 0x200161B, 0x200161F, 0x1001EDC, 0x40015B3, 0x40015B7, 0x60015BB, 0x60015C1, 0x40015C7, 0x40015CB, 0x40015CF, 0x40015D3, 0x40015D7, 0x40015DB, 0x40015DF, 0x40015E3, 0x40015E7, 0x0, 0x40015EB, 0x40015EF, 0x40015F3, 0x40015F7, 0x40015FB, 0x0, 0x40015FF, 0x0, 0x4001603, 0x4001607, 0x0, 0x400160B, 0x400160F, 0x0, 0x4001613, 0x4001617, 0x400161B, 0x40015BB, 0x400161F, 0x4001623, 0x4001627, 0x400162B, 0x400162F, 0x4002D18, 0x2002D1C, 0x2002D1C, 0x2002D1E, 0x2002D1E, 0x2002D1E, 0x2002D1E, 0x2002D20, 0x2002D20, 0x2002D20, 0x2002D20, 0x2002D22, 0x2002D22, 0x2002D22, 0x2002D22, 0x2002D24, 0x2002D24, 0x2002D24, 0x2002D24, 0x2002D26, 0x2002D26, 0x2002D26, 0x2002D26, 0x2002D28, 0x2002D28, 0x2002D28, 0x2002D28, 0x2002D2A, 0x2002D2A, 0x2002D2A, 0x2002D2A, 0x2002D2C, 0x2002D2C, 0x2002D2C, 0x2002D2C, 0x2002D2E, 0x2002D2E, 0x2002D2E, 0x2002D2E, 0x2002D30, 0x2002D30, 0x2002D30, 0x2002D30, 0x2002D32, 0x2002D32, 0x2002D32, 0x2002D32, 0x2002D34, 0x2002D34, 0x2002D34, 0x2002D34, 0x2002D36, 0x2002D36, 0x2002D38, 0x2002D38, 0x2002D3A, 0x2002D3A, 0x2002D3C, 0x2002D3C, 0x2002D3E, 0x2002D3E, 0x2002D40, 0x2002D40, 0x2002D42, 0x2002D42, 0x2002D42, 0x2002D42, 0x2002D44, 0x2002D44, 0x2002D44, 0x2002D44, 0x2002D46, 0x2002D46, 0x2002D46, 0x2002D46, 0x2002D48, 0x2002D48, 0x2002D48, 0x2002D48, 0x2002D4A, 0x2002D4A, 0x2002D4C, 0x2002D4C, 0x2002D4C, 0x2002D4C, 0x4000465, 0x4000465, 0x2000469, 0x2000469, 0x2000469, 0x2000469, 0x2002D4E, 0x2002D4E, 0x2002D4E, 0x2002D4E, 0x200046D, 0x200046D, 0x400046D, 0x400046D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2002D50, 0x2002D50, 0x2002D50, 0x2002D50, 0x2001DA5, 0x2001DA5, 0x2002D52, 0x2002D52, 0x2002D54, 0x2002D54, 0x4001DA5, 0x2002D56, 0x2002D56, 0x2002D58, 0x2002D58, 0x2002D5A, 0x2002D5A, 0x2002D5C, 0x2002D5C, 0x2002D5C, 0x2002D5C, 0x2002D5E, 0x2002D5E, 0x6002D60, 0x6002D60, 0x6000461, 0x6000461, 0x6002D66, 0x6002D66, 0x6002D6C, 0x6002D6C, 0x6002D72, 0x6002D72, 0x6002D78, 0x6002D78, 0x6002D7E, 0x6002D7E, 0x6002D7E, 0x6002D84, 0x6002D84, 0x6002D84, 0x2002D8A, 0x2002D8A, 0x2002D8A, 0x2002D8A, 0x6002D8C, 0x6002D92, 0x6002D98, 0x6002D84, 0x6002D9E, 0x4002DA4, 0x4002DA8, 0x4002DAC, 0x4002DB0, 0x4002DB4, 0x4002DB8, 0x4002DBC, 0x4002DC0, 0x4002DC4, 0x4002DC8, 0x4002DCC, 0x4002DD0, 0x4002DD4, 0x4002DD8, 0x4002DDC, 0x4002DE0, 0x4002DE4, 0x4002DE8, 0x4002DE6, 0x4002DEC, 0x4002DF0, 0x4002DF4, 0x4002DF8, 0x4002DFC, 0x4002E00, 0x4002E04, 0x4002E08, 0x4002E0C, 0x4002E10, 0x4002E14, 0x4002E18, 0x4002E1C, 0x4002E20, 0x4002E24, 0x4002E28, 0x4002E2C, 0x4002E30, 0x4002E34, 0x4002E38, 0x4002E3C, 0x4002E40, 0x4002E44, 0x4002E48, 0x4002E4C, 0x4002E50, 0x4002E54, 0x4002E58, 0x4002E5C, 0x4002E60, 0x4002E64, 0x4002E68, 0x4002E6C, 0x4002E70, 0x4002E74, 0x4002E78, 0x4002E7C, 0x4002E80, 0x4002E84, 0x4002E88, 0x4002E8C, 0x4002E90, 0x4002E94, 0x4002E98, 0x4002E9C, 0x4002EA0, 0x4002DEA, 0x4002DEE, 0x4002EA4, 0x4002EA8, 0x4002D9C, 0x4002EAC, 0x4002EB0, 0x4002EB4, 0x4002EB8, 0x4002EBC, 0x4002EC0, 0x4002EC4, 0x4002EC8, 0x4002ECC, 0x4002ED0, 0x4002DE2, 0x4002ED4, 0x4002ED8, 0x4002E9E, 0x4002EDC, 0x4002ED2, 0x4002EE0, 0x4002EE4, 0x4002EE8, 0x5002EEC, 0x5002EF1, 0x5002EF6, 0x5002EFB, 0x5002F00, 0x5002F05, 0x6002F0A, 0x6002F10, 0x6002D98, 0x6002F16, 0x6002D84, 0x6002D9E, 0x4002F1C, 0x4002F20, 0x4002DB0, 0x4002F24, 0x4002DB4, 0x4002DB8, 0x4002F28, 0x4002F2C, 0x4002DC8, 0x4002F30, 0x4002DCC, 0x4002DD0, 0x4002F34, 0x4002F38, 0x4002DD8, 0x4002F3C, 0x4002DDC, 0x4002DE0, 0x4002E50, 0x4002E54, 0x4002E60, 0x4002E64, 0x4002E68, 0x4002E78, 0x4002E7C, 0x4002E80, 0x4002E84, 0x4002E94, 0x4002E98, 0x4002E9C, 0x4002F40, 0x4002EA4, 0x4002F44, 0x4002F48, 0x4002EB8, 0x4002F4C, 0x4002EBC, 0x4002EC0, 0x4002EE8, 0x4002F50, 0x4002F54, 0x4002E9E, 0x4002F58, 0x4002EDC, 0x4002ED2, 0x6002D8C, 0x6002D92, 0x6002F5C, 0x6002D98, 0x6002F62, 0x4002DA4, 0x4002DA8, 0x4002DAC, 0x4002DB0, 0x4002F68, 0x4002DBC, 0x4002DC0, 0x4002DC4, 0x4002DC8, 0x4002F6C, 0x4002DD8, 0x4002DE4, 0x4002DE8, 0x4002DE6, 0x4002DEC, 0x4002DF0, 0x4002DF8, 0x4002DFC, 0x4002E00, 0x4002E04, 0x4002E08, 0x4002E0C, 0x4002F70, 0x4002E10, 0x4002E14, 0x4002E18, 0x4002E1C, 0x4002E20, 0x4002E24, 0x4002E2C, 0x4002E30, 0x4002E34, 0x4002E38, 0x4002E3C, 0x4002E40, 0x4002E44, 0x4002E48, 0x4002E4C, 0x4002E58, 0x4002E5C, 0x4002E6C, 0x4002E70, 0x4002E74, 0x4002E78, 0x4002E7C, 0x4002E88, 0x4002E8C, 0x4002E90, 0x4002E94, 0x4002F74, 0x4002EA0, 0x4002DEA, 0x4002DEE, 0x4002EA4, 0x4002EAC, 0x4002EB0, 0x4002EB4, 0x4002EB8, 0x4002F78, 0x4002EC4, 0x4002EC8, 0x4002F7C, 0x4002DE2, 0x4002F80, 0x4002ED8, 0x4002E9E, 0x4002EC2, 0x6002D98, 0x6002F62, 0x4002DB0, 0x4002F68, 0x4002DC8, 0x4002F6C, 0x4002DD8, 0x4002F84, 0x4002E08, 0x4002F88, 0x4002F8C, 0x4002F90, 0x4002E78, 0x4002E7C, 0x4002E94, 0x4002EB8, 0x4002F78, 0x4002E9E, 0x4002EC2, 0x6002F94, 0x6002F9A, 0x6002FA0, 0x4002FA6, 0x4002FAA, 0x4002FAE, 0x4002FB2, 0x4002FB6, 0x4002FBA, 0x4002FBE, 0x4002FC2, 0x4002FC6, 0x4002FCA, 0x4002FCE, 0x4002D96, 0x4002FD2, 0x4002D90, 0x4002FD6, 0x4002EDA, 0x4002FDA, 0x4002FDE, 0x4002FE2, 0x4002FE6, 0x4002FEA, 0x4002FEE, 0x4002FF2, 0x4002F8C, 0x4002FF6, 0x4002FFA, 0x4002FFE, 0x4003002, 0x4002FA6, 0x4002FAA, 0x4002FAE, 0x4002FB2, 0x4002FB6, 0x4002FBA, 0x4002FBE, 0x4002FC2, 0x4002FC6, 0x4002FCA, 0x4002FCE, 0x4002D96, 0x4002FD2, 0x4002D90, 0x4002FD6, 0x4002EDA, 0x4002FDA, 0x4002FDE, 0x4002FE2, 0x4002FE6, 0x4002FEA, 0x4002FEE, 0x4002FF2, 0x4002F8C, 0x4002FF6, 0x4002FFA, 0x4002FFE, 0x4003002, 0x4002FEA, 0x4002FEE, 0x4002FF2, 0x4002F8C, 0x4002F88, 0x4002F90, 0x4002E28, 0x4002DFC, 0x4002E00, 0x4002E04, 0x4002FEA, 0x4002FEE, 0x4002FF2, 0x4002E28, 0x4002E2C, 0x4003006, 0x4003006, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x600300A, 0x6003010, 0x6003010, 0x6003016, 0x600301C, 0x6003022, 0x6003028, 0x600302E, 0x6002DE8, 0x6002DE8, 0x6003034, 0x600303A, 0x6003040, 0x6003046, 0x600304C, 0x6003052, 0x6003052, 0x6003058, 0x600305E, 0x600305E, 0x6003064, 0x6003064, 0x600306A, 0x6003070, 0x6003070, 0x6003076, 0x600307C, 0x600307C, 0x6003082, 0x6003082, 0x6003088, 0x600308E, 0x600308E, 0x6003094, 0x6003094, 0x600309A, 0x60030A0, 0x60030A6, 0x60030AC, 0x60030AC, 0x60030B2, 0x60030B8, 0x60030BE, 0x60030C4, 0x60030CA, 0x60030CA, 0x60030D0, 0x60030D6, 0x60030DC, 0x60030E2, 0x60030E8, 0x60030EE, 0x60030EE, 0x60030F4, 0x60030F4, 0x60030FA, 0x60030FA, 0x6003100, 0x6002DEA, 0x6003106, 0x600310C, 0x6002EA0, 0x6002DEE, 0x6003112, 0x0, 0x0, 0x6003118, 0x600311E, 0x6003124, 0x600312A, 0x6003130, 0x6003136, 0x6003136, 0x600313C, 0x6003142, 0x6003148, 0x600314E, 0x600314E, 0x6003154, 0x600315A, 0x6003160, 0x6003166, 0x600316C, 0x6003172, 0x6003178, 0x600317E, 0x6003184, 0x600318A, 0x6003190, 0x6003196, 0x600319C, 0x60031A2, 0x60031A8, 0x60031AE, 0x60031B4, 0x60031BA, 0x60031C0, 0x60031C6, 0x60031CC, 0x60031D2, 0x60030D0, 0x60030DC, 0x60031D8, 0x60031DE, 0x60031E4, 0x60031EA, 0x60031F0, 0x60031F6, 0x60031F0, 0x60031E4, 0x60031FC, 0x6003202, 0x6003208, 0x600320E, 0x6003214, 0x60031F6, 0x60030A6, 0x600306A, 0x600321A, 0x6003220, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6003226, 0x600322C, 0x8003232, 0x800323A, 0x8003242, 0x800324A, 0x8003252, 0x800325A, 0x8003262, 0x600326A, 0x21003270, 0xF003291, 0x80032A0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10032A8, 0x30032A9, 0x30032AC, 0x1002085, 0x1000326, 0x1001ECB, 0x1001ED0, 0x30032AF, 0x30032B2, 0x3001EAA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2001EAA, 0x30032B5, 0x30032B8, 0x10032BB, 0x10032BB, 0x1001EE0, 0x1001EE1, 0x10032BC, 0x10032BD, 0x30032BE, 0x30032C1, 0x30032C4, 0x30032C7, 0x30032CA, 0x30032CD, 0x3000F42, 0x3000F45, 0x30032D0, 0x30032D3, 0x30032D6, 0x30032D9, 0x0, 0x0, 0x10032DC, 0x10032DD, 0x3001ECD, 0x3001ECD, 0x3001ECD, 0x3001ECD, 0x10032BB, 0x10032BB, 0x10032BB, 0x10032A8, 0x30032A9, 0x1001EAA, 0x0, 0x1000326, 0x1002085, 0x1001ED0, 0x1001ECB, 0x30032B5, 0x1001EE0, 0x1001EE1, 0x10032BC, 0x10032BD, 0x30032BE, 0x30032C1, 0x10032DE, 0x10032DF, 0x10032E0, 0x1001EDC, 0x10032E1, 0x1000EC4, 0x1000EC7, 0x1000EB7, 0x0, 0x10032E2, 0x10032E3, 0x10032E4, 0x10032E5, 0x0, 0x0, 0x0, 0x0, 0x30032E6, 0x40032E9, 0x3002EEC, 0x0, 0x3002EF1, 0x0, 0x3002EF6, 0x4002F94, 0x3002EFB, 0x4002F9A, 0x3002F00, 0x4002FA0, 0x3002F05, 0x40032ED, 0x30032F1, 0x40032F4, 0x20032F8, 0x4000451, 0x4000451, 0x4000455, 0x4000455, 0x4000459, 0x4000459, 0x400045D, 0x400045D, 0x4000461, 0x4000461, 0x4000461, 0x4000461, 0x2000451, 0x2000451, 0x2002DA4, 0x2002DA4, 0x2002DA4, 0x2002DA4, 0x20032FA, 0x20032FA, 0x2002DBC, 0x2002DBC, 0x2002DBC, 0x2002DBC, 0x2002DD4, 0x2002DD4, 0x2002DD4, 0x2002DD4, 0x2002D90, 0x2002D90, 0x2002D90, 0x2002D90, 0x2002D96, 0x2002D96, 0x2002D96, 0x2002D96, 0x2002DAE, 0x2002DAE, 0x2002DAE, 0x2002DAE, 0x2003248, 0x2003248, 0x2002EE0, 0x2002EE0, 0x2002EE4, 0x2002EE4, 0x2002F14, 0x2002F14, 0x2002DFC, 0x2002DFC, 0x2002DFC, 0x2002DFC, 0x2002F8C, 0x2002F8C, 0x2002F8C, 0x2002F8C, 0x2002E0C, 0x2002E0C, 0x2002E0C, 0x2002E0C, 0x2002E14, 0x2002E14, 0x2002E14, 0x2002E14, 0x2002E24, 0x2002E24, 0x2002E24, 0x2002E24, 0x2002E2C, 0x2002E2C, 0x2002E2C, 0x2002E2C, 0x2002E30, 0x2002E30, 0x2002E30, 0x2002E30, 0x2002E38, 0x2002E38, 0x2002E38, 0x2002E38, 0x2002E40, 0x2002E40, 0x2002E40, 0x2002E40, 0x2002E58, 0x2002E58, 0x2002E58, 0x2002E58, 0x2002E68, 0x2002E68, 0x2002E68, 0x2002E68, 0x2002E7A, 0x2002E7A, 0x2002E7A, 0x2002E7A, 0x2002D9C, 0x2002D9C, 0x2002D9C, 0x2002D9C, 0x2002EAC, 0x2002EAC, 0x2002EAC, 0x2002EAC, 0x2002EC4, 0x2002EC4, 0x2002EC4, 0x2002EC4, 0x2000459, 0x2000459, 0x2002D5E, 0x2002D5E, 0x2000461, 0x2000461, 0x2000461, 0x2000461, 0x60032FC, 0x60032FC, 0x6003302, 0x6003302, 0x6003308, 0x6003308, 0x4003298, 0x4003298, 0x0, 0x0, 0x0, 0x0, 0x1001ECB, 0x100330E, 0x10032DE, 0x10032E3, 0x10032E4, 0x10032DF, 0x100330F, 0x1001EE0, 0x1001EE1, 0x10032E0, 0x1001EDC, 0x10032A8, 0x10032E1, 0x1001EAA, 0x1001EE5, 0x1001ED6, 0x1001D2E, 0x1001D24, 0x1001D25, 0x1001D33, 0x1001ED7, 0x1001ED8, 0x1001ED9, 0x1001EDA, 0x1001EDB, 0x1002085, 0x1000326, 0x1000EC4, 0x1000EB7, 0x1000EC7, 0x1001ED0, 0x10032E5, 0x1000000, 0x1000633, 0x1000012, 0x10000C9, 0x1000015, 0x1000697, 0x10000ED, 0x1000105, 0x1000021, 0x1000126, 0x100012C, 0x1000132, 0x10006FF, 0x100002D, 0x1000030, 0x1000751, 0x1001EFC, 0x1000168, 0x100017A, 0x1000192, 0x100003F, 0x10007E1, 0x10001C2, 0x100080B, 0x100004B, 0x10001D1, 0x10032DC, 0x10032E2, 0x10032DD, 0x1003310, 0x10032BB, 0x1000E3D, 0x100004E, 0x1000636, 0x1000060, 0x10000CC, 0x1000063, 0x100069A, 0x10000F0, 0x1000108, 0x100006F, 0x1000129, 0x100012F, 0x1000135, 0x1000702, 0x100007B, 0x100007E, 0x1000754, 0x1002068, 0x100016B, 0x100017D, 0x1000195, 0x100008D, 0x10007E4, 0x10001C5, 0x100080E, 0x1000099, 0x10001D4, 0x10032BC, 0x1003311, 0x10032BD, 0x1003312, 0x3003313, 0x3003316, 0x30032AC, 0x30032D0, 0x30032D3, 0x30032A9, 0x3003319, 0x300109D, 0x30026CF, 0x3002915, 0x300331C, 0x300292A, 0x3002705, 0x300331F, 0x300278F, 0x30029FF, 0x300274A, 0x30026C0, 0x3002675, 0x3002678, 0x3001085, 0x300267B, 0x300267E, 0x3000FEF, 0x3000FF5, 0x3000FFB, 0x3001001, 0x3001007, 0x300100D, 0x3001013, 0x3001019, 0x300101F, 0x3001025, 0x300102B, 0x3001031, 0x3001037, 0x300103D, 0x3001043, 0x3002681, 0x3002684, 0x3002687, 0x300268A, 0x300268D, 0x3001049, 0x3001055, 0x3001061, 0x300106D, 0x3001079, 0x3002690, 0x3002693, 0x3002696, 0x3002699, 0x300269C, 0x300269F, 0x30026A2, 0x30026A5, 0x30026A8, 0x30026AB, 0x30026AE, 0x30026B1, 0x30026B4, 0x300108B, 0x30026D5, 0x3000F50, 0x3000FB0, 0x3002383, 0x30022EA, 0x30022ED, 0x30022F0, 0x30022F3, 0x30022F6, 0x30022F9, 0x30022FC, 0x30022FF, 0x3002302, 0x3002305, 0x3002308, 0x300230B, 0x300230E, 0x3002311, 0x3002314, 0x3002317, 0x300231A, 0x300231D, 0x3002320, 0x3002323, 0x3002326, 0x3002329, 0x300232C, 0x300232F, 0x3002332, 0x3002335, 0x3002338, 0x300233B, 0x300233E, 0x3002341, 0x0, 0x0, 0x0, 0x3002344, 0x3002347, 0x300234A, 0x300234D, 0x3002350, 0x3002353, 0x0, 0x0, 0x3002356, 0x3002359, 0x300235C, 0x300235F, 0x3002362, 0x3002365, 0x0, 0x0, 0x3002368, 0x300236B, 0x300236E, 0x3002371, 0x3002374, 0x3002377, 0x0, 0x0, 0x300237A, 0x300237D, 0x3002380, 0x0, 0x0, 0x0, 0x2003322, 0x2003324, 0x2003326, 0x3001D21, 0x2003328, 0x200332A, 0x300332C, 0x0, 0x300332F, 0x3000E6C, 0x3003332, 0x3000E71, 0x3003335, 0x3003338, 0x300333B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8001633, 0x0, 0x800163B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8001643, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x800164B, 0x8001653, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x800165B, 0x8001663, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x800166B, 0x8001673, 0x0, 0x800167B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8001683, 0x800168B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8001693, 0x800169B, 0xC00333E, 0xC0016AF, 0xC0016BB, 0xC0016C7, 0xC0016D3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80016DF, 0x80016E7, 0xC0016EF, 0xC0016FB, 0xC001707, 0xC001713, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000F0, 0x1000108, 0x100006F, 0x1000129, 0x100012F, 0x1000135, 0x1000702, 0x100007B, 0x100007E, 0x1000754, 0x1002068, 0x100016B, 0x100017D, 0x1000195, 0x100008D, 0x10007E4, 0x10001C5, 0x100080E, 0x1000099, 0x10001D4, 0x1000000, 0x1000633, 0x1000012, 0x10000C9, 0x1000015, 0x1000697, 0x10000ED, 0x1000105, 0x1000021, 0x1000126, 0x100012C, 0x1000132, 0x10006FF, 0x100002D, 0x1000030, 0x1000751, 0x1001EFC, 0x1000168, 0x100017A, 0x1000192, 0x100003F, 0x10007E1, 0x10001C2, 0x100080B, 0x100004B, 0x10001D1, 0x100004E, 0x1000636, 0x1000060, 0x10000CC, 0x1000063, 0x100069A, 0x10000F0, 0x0, 0x100006F, 0x1000129, 0x100012F, 0x1000135, 0x1000702, 0x100007B, 0x100007E, 0x1000754, 0x1002068, 0x100016B, 0x100004B, 0x10001D1, 0x100004E, 0x1000636, 0x1000060, 0x10000CC, 0x1000063, 0x100069A, 0x10000F0, 0x1000108, 0x100006F, 0x1000129, 0x100012F, 0x1000135, 0x1000702, 0x100007B, 0x100007E, 0x1000754, 0x1002068, 0x100016B, 0x100017D, 0x1000195, 0x100008D, 0x10007E4, 0x10001C5, 0x100080E, 0x1000099, 0x10001D4, 0x1000000, 0x0, 0x1000012, 0x10000C9, 0x0, 0x0, 0x10000ED, 0x0, 0x0, 0x1000126, 0x100012C, 0x0, 0x0, 0x100002D, 0x1000030, 0x1000751, 0x1001EFC, 0x0, 0x100017A, 0x1000192, 0x100003F, 0x10007E1, 0x10001C2, 0x100080B, 0x100004B, 0x10001D1, 0x100004E, 0x1000636, 0x1000060, 0x10000CC, 0x0, 0x100069A, 0x0, 0x1000108, 0x100006F, 0x1000129, 0x100012F, 0x1000135, 0x1000702, 0x100007B, 0x0, 0x1000754, 0x1002068, 0x100016B, 0x100017D, 0x1000195, 0x100008D, 0x10007E4, 0x10001C5, 0x100080E, 0x1000099, 0x10001D4, 0x1000000, 0x1000633, 0x1000012, 0x10000C9, 0x1000015, 0x1000697, 0x10000ED, 0x1000105, 0x1000021, 0x1000126, 0x100012C, 0x1000132, 0x10006FF, 0x100002D, 0x1000030, 0x1000751, 0x10001C5, 0x100080E, 0x1000099, 0x10001D4, 0x1000000, 0x1000633, 0x0, 0x10000C9, 0x1000015, 0x1000697, 0x10000ED, 0x0, 0x0, 0x1000126, 0x100012C, 0x1000132, 0x10006FF, 0x100002D, 0x1000030, 0x1000751, 0x1001EFC, 0x0, 0x100017A, 0x1000192, 0x100003F, 0x10007E1, 0x10001C2, 0x100080B, 0x100004B, 0x0, 0x100004E, 0x1000636, 0x1000060, 0x10000CC, 0x1000063, 0x100069A, 0x10000F0, 0x1000108, 0x100006F, 0x1000129, 0x100012F, 0x1000135, 0x1000702, 0x100007B, 0x100007E, 0x1000754, 0x1002068, 0x100016B, 0x100017D, 0x1000195, 0x100008D, 0x10007E4, 0x10001C5, 0x100080E, 0x1000099, 0x10001D4, 0x1000000, 0x1000633, 0x0, 0x10000C9, 0x1000015, 0x1000697, 0x10000ED, 0x0, 0x1000021, 0x1000126, 0x100012C, 0x1000132, 0x10006FF, 0x0, 0x1000030, 0x0, 0x0, 0x0, 0x100017A, 0x1000192, 0x100003F, 0x10007E1, 0x10001C2, 0x100080B, 0x100004B, 0x0, 0x100004E, 0x1000636, 0x1000060, 0x10000CC, 0x1000063, 0x100069A, 0x10000F0, 0x1000108, 0x100006F, 0x1000129, 0x100012F, 0x1000135, 0x1000702, 0x100007B, 0x100004B, 0x10001D1, 0x100004E, 0x1000636, 0x1000060, 0x10000CC, 0x1000063, 0x100069A, 0x10000F0, 0x1000108, 0x100006F, 0x1000129, 0x100012F, 0x1000135, 0x1000702, 0x100007B, 0x100007E, 0x1000754, 0x1002068, 0x100016B, 0x100017D, 0x1000195, 0x100008D, 0x10007E4, 0x10001C5, 0x100080E, 0x1000099, 0x10001D4, 0x1000000, 0x1000633, 0x1000012, 0x10000C9, 0x10001C5, 0x100080E, 0x1000099, 0x10001D4, 0x200334A, 0x200334C, 0x0, 0x0, 0x200032B, 0x200334E, 0x2001F07, 0x2003350, 0x2000331, 0x2003352, 0x2000335, 0x2001D95, 0x2000339, 0x2003354, 0x2003356, 0x2003358, 0x200335A, 0x200335C, 0x200033D, 0x2001F09, 0x2000E35, 0x2001D95, 0x2001D97, 0x200335E, 0x2000341, 0x2003360, 0x2003362, 0x2003364, 0x2000345, 0x3003366, 0x2000357, 0x2001D89, 0x2001E12, 0x2001E14, 0x200035B, 0x2003369, 0x200035F, 0x2001D8B, 0x2000349, 0x2001D91, 0x200336B, 0x2001D29, 0x200336D, 0x200336F, 0x200036D, 0x2001D8F, 0x2000E17, 0x2001D93, 0x2003371, 0x2003373, 0x2000367, 0x2001D8D, 0x2001E16, 0x2003375, 0x2000375, 0x3003377, 0x200035B, 0x2001D8B, 0x2001D91, 0x2001D8D, 0x2000E17, 0x2001D8F, 0x200032B, 0x200334E, 0x2001F07, 0x2003350, 0x2000331, 0x2003352, 0x2000335, 0x2001D95, 0x2000339, 0x2003354, 0x2003356, 0x2003358, 0x200335A, 0x200335C, 0x200033D, 0x2001F09, 0x2000E35, 0x2001D95, 0x2001D97, 0x200335E, 0x2000341, 0x2003360, 0x2003362, 0x2003364, 0x2000345, 0x3003366, 0x2000357, 0x2001D89, 0x2001E12, 0x2001E14, 0x2001E16, 0x2003375, 0x2000375, 0x3003377, 0x200035B, 0x2001D8B, 0x2001D91, 0x2001D8D, 0x2000E17, 0x2001D8F, 0x200337A, 0x200337C, 0x0, 0x0, 0x1001ED6, 0x1001D2E, 0x1001D24, 0x1001D25, 0x1001D33, 0x1001ED7, 0x1001ED8, 0x1001ED9, 0x1001EDA, 0x1001EDB, 0x1001ED6, 0x1001D2E, 0x1001D24, 0x1001D25, 0x1001D33, 0x1001ED7, 0x1001ED8, 0x1001ED9, 0x1001EDA, 0x1001EDB, 0x1001ED6, 0x1001D2E, 0x1001D24, 0x1001D25, 0x1001D33, 0x1001ED7, 0x1001ED8, 0x1001ED9, 0x1001EDA, 0x1001EDB, 0x1001ED6, 0x1001D2E, 0x1001D24, 0x1001D25, 0x1001D33, 0x1001ED7, 0x1001ED8, 0x1001ED9, 0x1001EDA, 0x1001EDB, 0x1001ED6, 0x1001D2E, 0x1001D24, 0x1001D25, 0x1001D33, 0x1001ED7, 0x1001ED8, 0x1001ED9, 0x1001EDA, 0x1001EDB, 0x2000451, 0x2002DA4, 0x2002D90, 0x2003248, 0x0, 0x2000459, 0x2002F14, 0x2002D96, 0x2002E24, 0x2000461, 0x2002E68, 0x2002E7A, 0x2002D9C, 0x2002EAC, 0x2002DFC, 0x2002E30, 0x2002E40, 0x2002E0C, 0x2002E58, 0x2002EE4, 0x2002F8C, 0x2002DBC, 0x2002DD4, 0x2002DAE, 0x2002EE0, 0x2002E14, 0x2002E2C, 0x2002E38, 0x200337E, 0x2002D4A, 0x2003380, 0x2003382, 0x0, 0x2002DA4, 0x2002D90, 0x0, 0x2002EC4, 0x0, 0x0, 0x2002D96, 0x0, 0x2000461, 0x2002E68, 0x2002E7A, 0x2002D9C, 0x2002EAC, 0x2002DFC, 0x2002E30, 0x2002E40, 0x2002E0C, 0x2002E58, 0x0, 0x2002F8C, 0x2002DBC, 0x2002DD4, 0x2002DAE, 0x0, 0x2002E14, 0x0, 0x2002E38, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2002D90, 0x0, 0x0, 0x0, 0x0, 0x2002D96, 0x0, 0x2000461, 0x0, 0x2002E7A, 0x0, 0x2002EAC, 0x2002DFC, 0x2002E30, 0x0, 0x2002E0C, 0x2002E58, 0x0, 0x2002F8C, 0x0, 0x0, 0x2002DAE, 0x0, 0x2002E14, 0x0, 0x2002E38, 0x0, 0x2002D4A, 0x0, 0x2003382, 0x0, 0x2002DA4, 0x2002D90, 0x0, 0x2002EC4, 0x0, 0x0, 0x2002D96, 0x2002E24, 0x2000461, 0x2002E68, 0x0, 0x2002D9C, 0x2002EAC, 0x2002DFC, 0x2002E30, 0x2002E40, 0x2002E0C, 0x2002E58, 0x0, 0x2002F8C, 0x2002DBC, 0x2002DD4, 0x2002DAE, 0x0, 0x2002E14, 0x2002E2C, 0x2002E38, 0x200337E, 0x0, 0x2003380, 0x0, 0x2000451, 0x2002DA4, 0x2002D90, 0x2003248, 0x2002EC4, 0x2000459, 0x2002F14, 0x2002D96, 0x2002E24, 0x2000461, 0x0, 0x2002E7A, 0x2002D9C, 0x2002EAC, 0x2002DFC, 0x2002E30, 0x2002E40, 0x2002E0C, 0x2002E58, 0x2002EE4, 0x2002F8C, 0x2002DBC, 0x2002DD4, 0x2002DAE, 0x2002EE0, 0x2002E14, 0x2002E2C, 0x2002E38, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2002DA4, 0x2002D90, 0x2003248, 0x0, 0x2000459, 0x2002F14, 0x2002D96, 0x2002E24, 0x2000461, 0x0, 0x2002E7A, 0x2002D9C, 0x2002EAC, 0x2002DFC, 0x2002E30, 0x2002E40, 0x2002E0C, 0x2002E58, 0x2002EE4, 0x2002F8C, 0x2002DBC, 0x2002DD4, 0x2002DAE, 0x2002EE0, 0x2002E14, 0x2002E2C, 0x2002E38, 0x0, 0x0, 0x0, 0x0, 0x2002017, 0x2003384, 0x2003386, 0x2003388, 0x200338A, 0x200338C, 0x200338E, 0x2003390, 0x2003392, 0x2003394, 0x2003396, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003398, 0x300339B, 0x300339E, 0x30033A1, 0x30033A4, 0x30033A7, 0x30033AA, 0x30033AD, 0x30033B0, 0x30033B3, 0x30033B6, 0x30033B9, 0x30033BC, 0x30033BF, 0x30033C2, 0x30033C5, 0x30033C8, 0x30033CB, 0x30033CE, 0x30033D1, 0x30033D4, 0x30033D7, 0x30033DA, 0x30033DD, 0x30033E0, 0x30033E3, 0x70033E6, 0x1000012, 0x1000168, 0x20033ED, 0x20033EF, 0x0, 0x1000000, 0x1000633, 0x1000012, 0x10000C9, 0x1000015, 0x1000697, 0x10000ED, 0x1000105, 0x1000021, 0x1000126, 0x100012C, 0x1000132, 0x10006FF, 0x100002D, 0x1000030, 0x1000751, 0x1001EFC, 0x1000168, 0x100017A, 0x1000192, 0x100003F, 0x10007E1, 0x10001C2, 0x100080B, 0x100004B, 0x10001D1, 0x20033F1, 0x2002BE9, 0x20033F3, 0x20033F5, 0x30033F7, 0x20033FA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20033FC, 0x20033FE, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2003400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6003402, 0x6003408, 0x300100D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x300213E, 0x300340E, 0x3003411, 0x600103D, 0x30020A5, 0x300180E, 0x3003414, 0x300241C, 0x3003417, 0x300341A, 0x300341D, 0x30012D7, 0x3003420, 0x3003423, 0x3001758, 0x3003426, 0x3003429, 0x300342C, 0x30021A7, 0x300342F, 0x3003432, 0x3003435, 0x3003438, 0x300343B, 0x300343E, 0x3002093, 0x3002404, 0x3003441, 0x3002611, 0x300240D, 0x3002614, 0x3003444, 0x300223A, 0x3003447, 0x300344A, 0x300344D, 0x3003450, 0x3003453, 0x300255A, 0x300215C, 0x3003456, 0x300177E, 0x3003459, 0x0, 0x0, 0x0, 0x0, 0x0, 0x900345C, 0x9003465, 0x900346E, 0x9003477, 0x9003480, 0x9003489, 0x9003492, 0x900349B, 0x90034A4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30034AD, 0x30034B0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x300171F, 0x3001722, 0x3001725, 0x4001728, 0x300172C, 0x3001403, 0x300172F, 0x3001732, 0x3001735, 0x3001738, 0x3001406, 0x300173B, 0x300173E, 0x4001741, 0x3001409, 0x3001745, 0x3001748, 0x300174B, 0x400174E, 0x3001752, 0x3001755, 0x3001758, 0x400175B, 0x300175F, 0x3001762, 0x3001765, 0x3001768, 0x30014B8, 0x400176B, 0x300176F, 0x3001772, 0x3001775, 0x3001778, 0x300177B, 0x300177E, 0x3001781, 0x3001784, 0x30014C7, 0x300140C, 0x300140F, 0x30014CA, 0x3001787, 0x300178A, 0x30011CC, 0x300178D, 0x3001412, 0x3001790, 0x3001793, 0x3001796, 0x3001799, 0x3001799, 0x3001799, 0x400179C, 0x30017A0, 0x30017A3, 0x30017A6, 0x40017A9, 0x30017AD, 0x30017B0, 0x30017B3, 0x30017B6, 0x30017B9, 0x30017BC, 0x30017BF, 0x30017C2, 0x30017C5, 0x30017C8, 0x30017CB, 0x30017CE, 0x30017D1, 0x30017D1, 0x30014D0, 0x30017D4, 0x30017D7, 0x30017DA, 0x30017DD, 0x3001418, 0x30017E0, 0x30017E3, 0x30017E6, 0x3001397, 0x30017E9, 0x30017EC, 0x30017EF, 0x30017F2, 0x30017F5, 0x30017F8, 0x30017FB, 0x30017FE, 0x4001801, 0x3001805, 0x3001808, 0x300180B, 0x300180E, 0x3001811, 0x3001814, 0x4001817, 0x400181B, 0x300181F, 0x3001822, 0x3001825, 0x3001828, 0x300182B, 0x300182E, 0x3001831, 0x3001834, 0x3001837, 0x3001837, 0x400183A, 0x300183E, 0x3001841, 0x30011C0, 0x3001844, 0x4001847, 0x300184B, 0x300184E, 0x3001851, 0x3001854, 0x3001857, 0x300185A, 0x3001427, 0x300185D, 0x3001860, 0x4001863, 0x3001867, 0x400186A, 0x300186E, 0x3001871, 0x3001874, 0x3001877, 0x300187A, 0x300187D, 0x3001880, 0x3001883, 0x3001886, 0x3001889, 0x300188C, 0x400188F, 0x3001893, 0x3001896, 0x3001899, 0x300189C, 0x300111E, 0x400189F, 0x30018A3, 0x40018A6, 0x40018A6, 0x30018AA, 0x30018AD, 0x30018AD, 0x30018B0, 0x40018B3, 0x40018B7, 0x30018BB, 0x30018BE, 0x30018C1, 0x30018C4, 0x30018C7, 0x30018CA, 0x30018CD, 0x30018D0, 0x30018D3, 0x30018D6, 0x300142A, 0x40018D9, 0x30018DD, 0x30018E0, 0x30018E3, 0x30014F4, 0x30018E3, 0x30018E6, 0x3001430, 0x30018E9, 0x30018EC, 0x30018EF, 0x30018F2, 0x3001433, 0x30010CD, 0x30018F5, 0x30018F8, 0x30018FB, 0x30018FE, 0x3001901, 0x3001904, 0x4001907, 0x300190B, 0x300190E, 0x3001911, 0x3001914, 0x3001917, 0x400191A, 0x300191E, 0x3001921, 0x3001924, 0x3001927, 0x300192A, 0x300192D, 0x3001930, 0x3001933, 0x3001936, 0x3001436, 0x3001939, 0x400193C, 0x3001940, 0x3001943, 0x3001946, 0x3001949, 0x300143C, 0x300194C, 0x300194F, 0x3001952, 0x3001955, 0x3001958, 0x300195B, 0x300195E, 0x3001961, 0x3001121, 0x300150C, 0x3001964, 0x3001967, 0x300196A, 0x400196D, 0x3001971, 0x3001974, 0x3001977, 0x300197A, 0x300143F, 0x400197D, 0x3001981, 0x3001984, 0x3001987, 0x3001590, 0x300198A, 0x300198D, 0x3001990, 0x3001993, 0x4001996, 0x300199A, 0x300199D, 0x30019A0, 0x40019A3, 0x30019A7, 0x30019AA, 0x30019AD, 0x30019B0, 0x30011F3, 0x30019B3, 0x40019B6, 0x40019BA, 0x40019BE, 0x30019C2, 0x40019C5, 0x30019C9, 0x30019CC, 0x30019CF, 0x30019D2, 0x30019D5, 0x3001442, 0x30012F8, 0x30019D8, 0x30019DB, 0x30019DE, 0x40019E1, 0x30019E5, 0x30019E8, 0x30019EB, 0x30019EE, 0x3001518, 0x30019F1, 0x40019F4, 0x30019F8, 0x30019FB, 0x40019FE, 0x4001A02, 0x3001A06, 0x3001A09, 0x300151B, 0x3001A0C, 0x3001A0F, 0x3001A12, 0x3001A15, 0x3001A18, 0x3001A1B, 0x4001A1E, 0x3001A22, 0x4001A25, 0x3001A29, 0x4001A2C, 0x3001A30, 0x3001521, 0x3001A33, 0x4001A36, 0x3001A3A, 0x3001A3D, 0x4001A40, 0x4001A44, 0x3001A48, 0x3001A4B, 0x3001A4E, 0x3001A51, 0x3001A54, 0x3001A54, 0x3001A57, 0x3001A5A, 0x3001527, 0x3001A5D, 0x3001A60, 0x3001A63, 0x3001A66, 0x4001A69, 0x3001A6D, 0x4001A70, 0x30011C9, 0x4001A74, 0x3001A78, 0x4001A7B, 0x4001A7F, 0x4001A83, 0x3001A87, 0x3001A8A, 0x3001539, 0x4001A8D, 0x4001A91, 0x4001A95, 0x4001A99, 0x3001A9D, 0x3001AA0, 0x3001AA0, 0x300153C, 0x3001596, 0x3001AA3, 0x3001AA6, 0x3001AA9, 0x4001AAC, 0x3001AB0, 0x3001157, 0x3001542, 0x3001AB3, 0x4001AB6, 0x3001463, 0x4001ABA, 0x4001ABE, 0x30013D9, 0x3001AC2, 0x3001AC5, 0x300146F, 0x3001AC8, 0x3001ACB, 0x4001ACE, 0x4001AD2, 0x4001AD2, 0x3001AD6, 0x3001AD9, 0x4001ADC, 0x3001AE0, 0x3001AE3, 0x3001AE6, 0x4001AE9, 0x3001AED, 0x3001AF0, 0x3001AF3, 0x3001AF6, 0x3001AF9, 0x4001AFC, 0x3001B00, 0x3001B03, 0x3001B06, 0x3001B09, 0x3001B0C, 0x3001B0F, 0x4001B12, 0x4001B16, 0x3001B1A, 0x4001B1D, 0x3001B21, 0x4001B24, 0x3001B28, 0x3001B2B, 0x3001481, 0x4001B2E, 0x4001B32, 0x3001B36, 0x4001B39, 0x3001B3D, 0x4001B40, 0x3001B44, 0x3001B47, 0x3001B4A, 0x3001B4D, 0x3001B50, 0x3001B53, 0x4001B56, 0x4001B5A, 0x4001B5E, 0x4001B62, 0x30018AA, 0x3001B66, 0x3001B69, 0x3001B6C, 0x3001B6F, 0x3001B72, 0x3001B75, 0x3001B78, 0x3001B7B, 0x3001B7E, 0x3001B81, 0x3001B84, 0x4001B87, 0x30011FF, 0x3001B8B, 0x3001B8E, 0x3001B91, 0x3001B94, 0x3001B97, 0x3001B9A, 0x300148A, 0x3001B9D, 0x3001BA0, 0x3001BA3, 0x3001BA6, 0x4001BA9, 0x4001BAD, 0x4001BB1, 0x3001BB5, 0x3001BB8, 0x3001BBB, 0x3001BBE, 0x4001BC1, 0x3001BC5, 0x4001BC8, 0x3001BCC, 0x3001BCF, 0x4001BD2, 0x4001BD6, 0x3001BDA, 0x3001BDD, 0x3001148, 0x3001BE0, 0x3001BE3, 0x3001BE6, 0x3001BE9, 0x3001BEC, 0x3001BEF, 0x3001557, 0x3001BF2, 0x3001BF5, 0x3001BF8, 0x3001BFB, 0x3001BFE, 0x3001C01, 0x3001C04, 0x3001C07, 0x3001C0A, 0x4001C0D, 0x3001C11, 0x3001C14, 0x3001C17, 0x3001C1A, 0x3001C1D, 0x4001C20, 0x4001C24, 0x3001C28, 0x3001C2B, 0x3001C2E, 0x3001566, 0x3001569, 0x3001C31, 0x4001C34, 0x3001C38, 0x3001C3B, 0x3001C3E, 0x3001C41, 0x4001C44, 0x4001C48, 0x3001C4C, 0x3001C4F, 0x3001C52, 0x4001C55, 0x3001C59, 0x300156C, 0x4001C5C, 0x4001C60, 0x3001C64, 0x3001C67, 0x3001C6A, 0x4001C6D, 0x3001C71, 0x3001C74, 0x3001C77, 0x3001C7A, 0x3001C7D, 0x3001C80, 0x3001C83, 0x4001C86, 0x3001C8A, 0x3001C8D, 0x3001C90, 0x4001C93, 0x3001C97, 0x3001C9A, 0x3001C9D, 0x3001CA0, 0x4001CA3, 0x4001CA7, 0x3001CAB, 0x3001CAE, 0x3001CB1, 0x4001CB4, 0x3001CB8, 0x4001CBB, 0x300157E, 0x300157E, 0x3001CBF, 0x4001CC2, 0x3001CC6, 0x3001CC9, 0x3001CCC, 0x3001CCF, 0x3001CD2, 0x3001CD5, 0x3001CD8, 0x4001CDB, 0x3001581, 0x3001CDF, 0x3001CE2, 0x3001CE5, 0x3001CE8, 0x3001CEB, 0x4001CEE, 0x3001CF2, 0x4001CF5, 0x4001CF9, 0x4001CFD, 0x3001D01, 0x3001D04, 0x3001D07, 0x3001D0A, 0x3001D0D, 0x3001D10, 0x3001D13, 0x3001D16, 0x4001D19, 0x0, 0x0, }; const uint32_t* NFKDDataPtr = NFKDData; const uint32_t UppercaseIndex1[272] = { 0, 128, 256, 45, 45, 45, 45, 45, 45, 45, 384, 45, 45, 45, 45, 512, 640, 768, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, }; const uint32_t* UppercaseIndex1Ptr = UppercaseIndex1; const uint32_t UppercaseIndex2[896] = { 0x0, 0x0, 0x0, 0x20, 0x0, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0, 0x100, 0x120, 0x140, 0x160, 0x180, 0x1A0, 0x1C0, 0x1E0, 0x200, 0x220, 0x0, 0x0, 0x0, 0x0, 0x0, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, 0x0, 0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0x400, 0x0, 0x420, 0x440, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x460, 0x0, 0x0, 0x0, 0x0, 0x480, 0x4A0, 0x4C0, 0x4E0, 0x500, 0x520, 0x540, 0x560, 0x580, 0x5A0, 0x5C0, 0x5E0, 0x600, 0x620, 0x640, 0x660, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x680, 0x6A0, 0x6C0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6E0, 0x700, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x720, 0x740, 0x760, 0x780, 0x7A0, 0x7C0, 0x7E0, 0x800, 0x820, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x840, 0x860, 0x880, 0x0, 0x0, 0x0, 0x0, 0x8A0, 0x8C0, 0x8E0, 0x900, 0x920, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x940, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x960, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x980, 0x9A0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9C0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, }; const uint32_t* UppercaseIndex2Ptr = UppercaseIndex2; const uint32_t UppercaseData[2528] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000000, 0x1000633, 0x1000012, 0x10000C9, 0x1000015, 0x1000697, 0x10000ED, 0x1000105, 0x1000021, 0x1000126, 0x100012C, 0x1000132, 0x10006FF, 0x100002D, 0x1000030, 0x1000751, 0x1001EFC, 0x1000168, 0x100017A, 0x1000192, 0x100003F, 0x10007E1, 0x10001C2, 0x100080B, 0x100004B, 0x10001D1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2003358, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20033F5, 0x20034B3, 0x20034B5, 0x20034B7, 0x20034B9, 0x20034BB, 0x20034BD, 0x2000243, 0x20034BF, 0x20034C1, 0x20034C3, 0x20034C5, 0x20034C7, 0x20034C9, 0x20034CB, 0x20034CD, 0x20034CF, 0x20034D1, 0x20034D3, 0x20034D5, 0x20034D7, 0x20034D9, 0x20034DB, 0x20034DD, 0x0, 0x2000290, 0x20034DF, 0x20034E1, 0x20034E3, 0x20034E5, 0x20034E7, 0x20034E9, 0x20034EB, 0x0, 0x20034ED, 0x0, 0x20034EF, 0x0, 0x20034F1, 0x0, 0x20034F3, 0x0, 0x20034F5, 0x0, 0x20034F7, 0x0, 0x20034F9, 0x0, 0x20034FB, 0x0, 0x20034FD, 0x0, 0x20034FF, 0x0, 0x2003501, 0x0, 0x2003503, 0x0, 0x2003505, 0x0, 0x2003507, 0x0, 0x2003509, 0x0, 0x200350B, 0x0, 0x200350D, 0x0, 0x200350F, 0x0, 0x2003511, 0x0, 0x2002CE3, 0x0, 0x2003513, 0x0, 0x2003515, 0x0, 0x2003517, 0x0, 0x2003519, 0x0, 0x1000021, 0x0, 0x200351B, 0x0, 0x200351D, 0x0, 0x200351F, 0x0, 0x0, 0x2003521, 0x0, 0x2003523, 0x0, 0x2003525, 0x0, 0x2003527, 0x0, 0x2003529, 0x0, 0x200352B, 0x0, 0x200352D, 0x0, 0x200352F, 0x3003531, 0x0, 0x2003534, 0x0, 0x2003536, 0x0, 0x2003538, 0x0, 0x200353A, 0x0, 0x200353C, 0x0, 0x200353E, 0x0, 0x2003540, 0x0, 0x2003542, 0x0, 0x2003544, 0x0, 0x2003546, 0x0, 0x2003548, 0x0, 0x200354A, 0x0, 0x200354C, 0x0, 0x200354E, 0x0, 0x2003550, 0x0, 0x2003552, 0x0, 0x2003554, 0x0, 0x2003556, 0x0, 0x2003558, 0x0, 0x200355A, 0x0, 0x200355C, 0x0, 0x200355E, 0x0, 0x2003560, 0x0, 0x0, 0x2003562, 0x0, 0x2003564, 0x0, 0x2003566, 0x100017A, 0x2003568, 0x0, 0x0, 0x200356A, 0x0, 0x200356C, 0x0, 0x0, 0x200356E, 0x0, 0x0, 0x0, 0x2003570, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2003572, 0x0, 0x0, 0x2003574, 0x0, 0x0, 0x0, 0x2003576, 0x2003578, 0x0, 0x0, 0x0, 0x200357A, 0x0, 0x0, 0x200357C, 0x0, 0x200357E, 0x0, 0x2003580, 0x0, 0x0, 0x2003582, 0x0, 0x0, 0x0, 0x0, 0x2003584, 0x0, 0x0, 0x2003586, 0x0, 0x0, 0x0, 0x2003588, 0x0, 0x200358A, 0x0, 0x0, 0x200358C, 0x0, 0x0, 0x0, 0x200358E, 0x0, 0x2003590, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2003592, 0x2003592, 0x0, 0x2003594, 0x2003594, 0x0, 0x2003596, 0x2003596, 0x0, 0x2003598, 0x0, 0x200359A, 0x0, 0x200359C, 0x0, 0x200359E, 0x0, 0x20035A0, 0x0, 0x20035A2, 0x0, 0x20035A4, 0x0, 0x20035A6, 0x2001DEF, 0x0, 0x20035A8, 0x0, 0x20035AA, 0x0, 0x20035AC, 0x0, 0x20035AE, 0x0, 0x20035B0, 0x0, 0x20035B2, 0x0, 0x20035B4, 0x0, 0x20035B6, 0x0, 0x20035B8, 0x30035BA, 0x0, 0x20035BD, 0x20035BD, 0x0, 0x20035BF, 0x0, 0x0, 0x0, 0x20035C1, 0x0, 0x20035C3, 0x0, 0x20035C5, 0x0, 0x20035C7, 0x0, 0x20035C9, 0x0, 0x20035CB, 0x0, 0x20035CD, 0x0, 0x20035CF, 0x0, 0x20035D1, 0x0, 0x20035D3, 0x0, 0x20035D5, 0x0, 0x20035D7, 0x0, 0x20035D9, 0x0, 0x20035DB, 0x0, 0x20035DD, 0x0, 0x20035DF, 0x0, 0x20035E1, 0x0, 0x20035E3, 0x0, 0x20035E5, 0x0, 0x20035E7, 0x0, 0x0, 0x0, 0x2001DF1, 0x0, 0x20035E9, 0x0, 0x20035EB, 0x0, 0x20035ED, 0x0, 0x20035EF, 0x0, 0x20035F1, 0x0, 0x20035F3, 0x0, 0x20035F5, 0x0, 0x20035F7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20035F9, 0x0, 0x0, 0x30035FB, 0x30035FE, 0x0, 0x2003601, 0x0, 0x0, 0x0, 0x0, 0x2003603, 0x0, 0x2003605, 0x0, 0x2003607, 0x0, 0x2003609, 0x0, 0x200360B, 0x300360D, 0x3003610, 0x3003613, 0x2003616, 0x2003618, 0x0, 0x200361A, 0x200361C, 0x0, 0x200361E, 0x0, 0x2001EF3, 0x3003620, 0x0, 0x0, 0x0, 0x2003623, 0x3003625, 0x0, 0x2003628, 0x0, 0x300362A, 0x300362D, 0x0, 0x2003630, 0x2003632, 0x0, 0x3003634, 0x3003637, 0x0, 0x0, 0x200363A, 0x0, 0x300363C, 0x200363F, 0x0, 0x0, 0x2003641, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003643, 0x0, 0x0, 0x2003646, 0x0, 0x0, 0x2003648, 0x0, 0x0, 0x0, 0x300364A, 0x200364D, 0x200364F, 0x2003651, 0x2003653, 0x2003655, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000267, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003657, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000339, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200365A, 0x0, 0x200365C, 0x0, 0x0, 0x0, 0x200365E, 0x0, 0x0, 0x0, 0x2003660, 0x2003662, 0x2003664, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6003666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200366C, 0x200366E, 0x2003670, 0x2003672, 0x6003674, 0x200032B, 0x200334E, 0x2001F07, 0x2003350, 0x2000331, 0x2003352, 0x2000335, 0x2001D95, 0x2000339, 0x2003354, 0x2003356, 0x2003358, 0x200335A, 0x200335C, 0x200033D, 0x2001F09, 0x2000E35, 0x2001D97, 0x2001D97, 0x200335E, 0x2000341, 0x2003360, 0x2003362, 0x2003364, 0x2000345, 0x200367A, 0x200367C, 0x200367E, 0x2003680, 0x2003682, 0x0, 0x200334E, 0x2001D95, 0x0, 0x0, 0x0, 0x2003360, 0x2001F09, 0x2003684, 0x0, 0x2003686, 0x0, 0x2003688, 0x0, 0x200337A, 0x0, 0x200368A, 0x0, 0x200368C, 0x0, 0x200368E, 0x0, 0x2003690, 0x0, 0x2003692, 0x0, 0x2003694, 0x0, 0x2003696, 0x0, 0x2003698, 0x0, 0x200369A, 0x2003354, 0x2000E35, 0x200369C, 0x200369E, 0x0, 0x2000331, 0x0, 0x0, 0x20036A0, 0x0, 0x0, 0x20036A2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20003D1, 0x20036A4, 0x20036A6, 0x2000389, 0x20036A8, 0x2000381, 0x20003C9, 0x20003F9, 0x2000395, 0x20036AA, 0x2000391, 0x20036AC, 0x20036AE, 0x20036B0, 0x2000411, 0x20036B2, 0x20036B4, 0x20036B6, 0x20036B8, 0x2000399, 0x20036BA, 0x20036BC, 0x20036BE, 0x2000441, 0x20036C0, 0x20036C2, 0x20036C4, 0x2000449, 0x20036C6, 0x2000421, 0x20036C8, 0x20036CA, 0x20036CC, 0x20036CE, 0x20036D0, 0x20036D2, 0x20036D4, 0x20036D6, 0x200038D, 0x20036D8, 0x20036DA, 0x20036DC, 0x20036DE, 0x20036E0, 0x20036E2, 0x20036E4, 0x20036E6, 0x20036E8, 0x0, 0x20036EA, 0x0, 0x20036EC, 0x0, 0x20036EE, 0x0, 0x20036F0, 0x0, 0x20036F2, 0x0, 0x20036F4, 0x0, 0x20036F6, 0x0, 0x20036F8, 0x0, 0x20036FA, 0x0, 0x20036FC, 0x0, 0x20003C1, 0x0, 0x20036FE, 0x0, 0x2003700, 0x0, 0x2003702, 0x0, 0x2003704, 0x0, 0x2003706, 0x0, 0x2003708, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200370A, 0x0, 0x200370C, 0x0, 0x200370E, 0x0, 0x2003710, 0x0, 0x2003712, 0x0, 0x2003714, 0x0, 0x2003716, 0x0, 0x2003718, 0x0, 0x200371A, 0x0, 0x200371C, 0x0, 0x200371E, 0x0, 0x2003720, 0x0, 0x2003722, 0x0, 0x2003724, 0x0, 0x2003726, 0x0, 0x2003728, 0x0, 0x200372A, 0x0, 0x200372C, 0x0, 0x200372E, 0x0, 0x2003730, 0x0, 0x2003732, 0x0, 0x2003734, 0x0, 0x2003736, 0x0, 0x2003738, 0x0, 0x200373A, 0x0, 0x200373C, 0x0, 0x200373E, 0x0, 0x0, 0x2003740, 0x0, 0x2003742, 0x0, 0x2003744, 0x0, 0x2003746, 0x0, 0x2003748, 0x0, 0x200374A, 0x0, 0x200374C, 0x200374E, 0x0, 0x2003750, 0x0, 0x2003752, 0x0, 0x2003754, 0x0, 0x2003756, 0x0, 0x20003E9, 0x0, 0x2003758, 0x0, 0x200375A, 0x0, 0x200375C, 0x0, 0x200375E, 0x0, 0x2003760, 0x0, 0x2003762, 0x0, 0x2003764, 0x0, 0x2000419, 0x0, 0x2003766, 0x0, 0x2003768, 0x0, 0x200376A, 0x0, 0x200376C, 0x0, 0x200376E, 0x0, 0x2003770, 0x0, 0x2003772, 0x0, 0x2003774, 0x0, 0x2003776, 0x0, 0x2003778, 0x0, 0x200377A, 0x0, 0x200377C, 0x0, 0x200377E, 0x0, 0x2003780, 0x0, 0x2003782, 0x0, 0x2003784, 0x0, 0x2003786, 0x0, 0x2003788, 0x0, 0x200378A, 0x0, 0x200378C, 0x0, 0x200378E, 0x0, 0x2003790, 0x0, 0x2003792, 0x0, 0x2003794, 0x0, 0x2003796, 0x0, 0x2003798, 0x0, 0x200379A, 0x0, 0x200379C, 0x0, 0x200379E, 0x0, 0x20037A0, 0x0, 0x20037A2, 0x0, 0x20037A4, 0x0, 0x20037A6, 0x0, 0x20037A8, 0x0, 0x20037AA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20037AC, 0x20037AE, 0x20037B0, 0x20037B2, 0x20037B4, 0x20037B6, 0x20037B8, 0x20037BA, 0x20037BC, 0x20037BE, 0x20037C0, 0x20037C2, 0x20037C4, 0x20037C6, 0x20037C8, 0x20037CA, 0x20037CC, 0x20037CE, 0x20037D0, 0x20037D2, 0x20037D4, 0x20037D6, 0x20037D8, 0x20037DA, 0x20037DC, 0x20037DE, 0x20037E0, 0x20037E2, 0x20037E4, 0x20037E6, 0x20037E8, 0x20037EA, 0x20037EC, 0x20037EE, 0x20037F0, 0x20037F2, 0x20037F4, 0x20037F6, 0x40037F8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30037FC, 0x0, 0x0, 0x0, 0x30037FF, 0x0, 0x0, 0x0, 0x3003802, 0x0, 0x3003805, 0x0, 0x3003808, 0x0, 0x300380B, 0x0, 0x300380E, 0x0, 0x3003811, 0x0, 0x3003814, 0x0, 0x3003817, 0x0, 0x300381A, 0x0, 0x300381D, 0x0, 0x3003820, 0x0, 0x3003823, 0x0, 0x3003826, 0x0, 0x3003829, 0x0, 0x300382C, 0x0, 0x300382F, 0x0, 0x3003832, 0x0, 0x3003835, 0x0, 0x3003838, 0x0, 0x300383B, 0x0, 0x300383E, 0x0, 0x3003841, 0x0, 0x3003844, 0x0, 0x3003847, 0x0, 0x300384A, 0x0, 0x300384D, 0x0, 0x3003850, 0x0, 0x3003853, 0x0, 0x3003856, 0x0, 0x3003859, 0x0, 0x300385C, 0x0, 0x300385F, 0x0, 0x3003862, 0x0, 0x3003865, 0x0, 0x3003868, 0x0, 0x300386B, 0x0, 0x300386E, 0x0, 0x3003871, 0x0, 0x3003874, 0x0, 0x3003877, 0x0, 0x300387A, 0x0, 0x300387D, 0x0, 0x3003880, 0x0, 0x3003883, 0x0, 0x3003886, 0x0, 0x3003889, 0x0, 0x300388C, 0x0, 0x300388F, 0x0, 0x3003892, 0x0, 0x3003895, 0x0, 0x3003898, 0x0, 0x300389B, 0x0, 0x300389E, 0x0, 0x30038A1, 0x0, 0x30038A4, 0x0, 0x30038A7, 0x0, 0x30038AA, 0x0, 0x30038AD, 0x0, 0x30038B0, 0x0, 0x30038B3, 0x0, 0x30038B6, 0x0, 0x30038B9, 0x0, 0x30038BC, 0x0, 0x30038BF, 0x0, 0x30038C2, 0x0, 0x30038C5, 0x0, 0x30038C8, 0x0, 0x30038CB, 0x0, 0x30038CE, 0x0, 0x30038D1, 0x0, 0x30038D4, 0x0, 0x30038D7, 0x0, 0x30038DA, 0x0, 0x30038DD, 0x0, 0x30038E0, 0x30038E3, 0x30038E6, 0x30038E9, 0x30038EC, 0x30038EF, 0x3003892, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30038F2, 0x0, 0x30038F5, 0x0, 0x30038F8, 0x0, 0x30038FB, 0x0, 0x30038FE, 0x0, 0x3003901, 0x0, 0x3003904, 0x0, 0x3003907, 0x0, 0x300390A, 0x0, 0x300390D, 0x0, 0x3003910, 0x0, 0x3003913, 0x0, 0x3003916, 0x0, 0x3003919, 0x0, 0x300391C, 0x0, 0x300391F, 0x0, 0x3003922, 0x0, 0x3003925, 0x0, 0x3003928, 0x0, 0x300392B, 0x0, 0x300392E, 0x0, 0x3003931, 0x0, 0x3003934, 0x0, 0x3003937, 0x0, 0x300393A, 0x0, 0x300393D, 0x0, 0x3003940, 0x0, 0x3003943, 0x0, 0x3003946, 0x0, 0x3003949, 0x0, 0x300394C, 0x0, 0x300394F, 0x0, 0x3003952, 0x0, 0x3003955, 0x0, 0x3003958, 0x0, 0x300395B, 0x0, 0x300395E, 0x0, 0x3003961, 0x0, 0x3003964, 0x0, 0x3003967, 0x0, 0x300396A, 0x0, 0x300396D, 0x0, 0x3003970, 0x0, 0x3003973, 0x0, 0x3003976, 0x0, 0x3003979, 0x0, 0x300397C, 0x0, 0x300397F, 0x3003982, 0x3003985, 0x3003988, 0x300398B, 0x300398E, 0x3003991, 0x3003994, 0x3003997, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x300399A, 0x300399D, 0x30039A0, 0x30039A3, 0x30039A6, 0x30039A9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30039AC, 0x30039AF, 0x30039B2, 0x30039B5, 0x30039B8, 0x30039BB, 0x30039BE, 0x30039C1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30039C4, 0x30039C7, 0x30039CA, 0x30039CD, 0x30039D0, 0x30039D3, 0x30039D6, 0x30039D9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30039DC, 0x30039DF, 0x30039E2, 0x30039E5, 0x30039E8, 0x30039EB, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40039EE, 0x30039F2, 0x60039F5, 0x30039FB, 0x60039FE, 0x3003A04, 0x6003A07, 0x3003A0D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003A10, 0x3003A13, 0x3003A16, 0x3003A19, 0x3003A1C, 0x3003A1F, 0x3003A22, 0x3003A25, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003A28, 0x3003A2B, 0x3003A2E, 0x3003A31, 0x3003A34, 0x3003A37, 0x3003A3A, 0x3003A3D, 0x3003A40, 0x3003A43, 0x3003A46, 0x3003A49, 0x3003A4C, 0x3003A4F, 0x0, 0x0, 0x5003A52, 0x5003A57, 0x5003A5C, 0x5003A61, 0x5003A66, 0x5003A6B, 0x5003A70, 0x5003A75, 0x5003A52, 0x5003A57, 0x5003A5C, 0x5003A61, 0x5003A66, 0x5003A6B, 0x5003A70, 0x5003A75, 0x5003A7A, 0x5003A7F, 0x5003A84, 0x5003A89, 0x5003A8E, 0x5003A93, 0x5003A98, 0x5003A9D, 0x5003A7A, 0x5003A7F, 0x5003A84, 0x5003A89, 0x5003A8E, 0x5003A93, 0x5003A98, 0x5003A9D, 0x5003AA2, 0x5003AA7, 0x5003AAC, 0x5003AB1, 0x5003AB6, 0x5003ABB, 0x5003AC0, 0x5003AC5, 0x5003AA2, 0x5003AA7, 0x5003AAC, 0x5003AB1, 0x5003AB6, 0x5003ABB, 0x5003AC0, 0x5003AC5, 0x3003ACA, 0x3003ACD, 0x5003AD0, 0x4003AD5, 0x4003AD9, 0x0, 0x4003ADD, 0x6003AE1, 0x0, 0x0, 0x0, 0x0, 0x4003AD5, 0x0, 0x2000339, 0x0, 0x0, 0x0, 0x5003AE7, 0x4003AEC, 0x4003AF0, 0x0, 0x4003AF4, 0x6003AF8, 0x0, 0x0, 0x0, 0x0, 0x4003AEC, 0x0, 0x0, 0x0, 0x3003AFE, 0x3003B01, 0x6003B04, 0x6003666, 0x0, 0x0, 0x4003B0A, 0x6003B0E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003B14, 0x3003B17, 0x6003B1A, 0x6003674, 0x4003B20, 0x3003B24, 0x4003B27, 0x6003B2B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5003B31, 0x4003B36, 0x4003B3A, 0x0, 0x4003B3E, 0x6003B42, 0x0, 0x0, 0x0, 0x0, 0x4003B36, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003B48, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003B4B, 0x3003B4E, 0x3003B51, 0x3003B54, 0x3003B57, 0x3003B5A, 0x3003B5D, 0x3003B60, 0x3003B63, 0x3003B66, 0x3003B69, 0x3003B6C, 0x3003B6F, 0x3003B72, 0x3003B75, 0x3003B78, 0x0, 0x0, 0x0, 0x0, 0x3003B7B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003B7E, 0x3003B81, 0x3003B84, 0x3003B87, 0x3003B8A, 0x3003B8D, 0x3003B90, 0x3003B93, 0x3003B96, 0x3003B99, 0x3003B9C, 0x3003B9F, 0x3003BA2, 0x3003BA5, 0x3003BA8, 0x3003BAB, 0x3003BAE, 0x3003BB1, 0x3003BB4, 0x3003BB7, 0x3003BBA, 0x3003BBD, 0x3003BC0, 0x3003BC3, 0x3003BC6, 0x3003BC9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003BCC, 0x3003BCF, 0x3003BD2, 0x3003BD5, 0x3003BD8, 0x3003BDB, 0x3003BDE, 0x3003BE1, 0x3003BE4, 0x3003BE7, 0x3003BEA, 0x3003BED, 0x3003BF0, 0x3003BF3, 0x3003BF6, 0x3003BF9, 0x3003BFC, 0x3003BFF, 0x3003C02, 0x3003C05, 0x3003C08, 0x3003C0B, 0x3003C0E, 0x3003C11, 0x3003C14, 0x3003C17, 0x3003C1A, 0x3003C1D, 0x3003C20, 0x3003C23, 0x3003C26, 0x3003C29, 0x3003C2C, 0x3003C2F, 0x3003C32, 0x3003C35, 0x3003C38, 0x3003C3B, 0x3003C3E, 0x3003C41, 0x3003C44, 0x3003C47, 0x3003C4A, 0x3003C4D, 0x3003C50, 0x3003C53, 0x3003C56, 0x0, 0x0, 0x3003C59, 0x0, 0x0, 0x0, 0x2003C5C, 0x2003C5E, 0x0, 0x3003C60, 0x0, 0x3003C63, 0x0, 0x3003C66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003C69, 0x0, 0x0, 0x3003C6C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003C6F, 0x0, 0x3003C72, 0x0, 0x3003C75, 0x0, 0x3003C78, 0x0, 0x3003C7B, 0x0, 0x3003C7E, 0x0, 0x3003C81, 0x0, 0x3003C84, 0x0, 0x3003C87, 0x0, 0x3003C8A, 0x0, 0x3003C8D, 0x0, 0x3003C90, 0x0, 0x3003C93, 0x0, 0x3003C96, 0x0, 0x3003C99, 0x0, 0x3003C9C, 0x0, 0x3003C9F, 0x0, 0x3003CA2, 0x0, 0x3003CA5, 0x0, 0x3003CA8, 0x0, 0x3003CAB, 0x0, 0x3003CAE, 0x0, 0x3003CB1, 0x0, 0x3003CB4, 0x0, 0x3003CB7, 0x0, 0x3003CBA, 0x0, 0x3003CBD, 0x0, 0x3003CC0, 0x0, 0x3003CC3, 0x0, 0x3003CC6, 0x0, 0x3003CC9, 0x0, 0x3003CCC, 0x0, 0x3003CCF, 0x0, 0x3003CD2, 0x0, 0x3003CD5, 0x0, 0x3003CD8, 0x0, 0x3003CDB, 0x0, 0x3003CDE, 0x0, 0x3003CE1, 0x0, 0x3003CE4, 0x0, 0x3003CE7, 0x0, 0x3003CEA, 0x0, 0x3003CED, 0x0, 0x3003CF0, 0x0, 0x3003CF3, 0x0, 0x3003CF6, 0x0, 0x3003CF9, 0x0, 0x3003CFC, 0x0, 0x3003CFF, 0x0, 0x3003D02, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003D05, 0x0, 0x3003D08, 0x0, 0x0, 0x0, 0x0, 0x3003D0B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003D0E, 0x3003D11, 0x3003D14, 0x3003D17, 0x3003D1A, 0x3003D1D, 0x3003D20, 0x3003D23, 0x3003D26, 0x3003D29, 0x3003D2C, 0x3003D2F, 0x3003D32, 0x3003D35, 0x3003D38, 0x3003D3B, 0x3003D3E, 0x3003D41, 0x3003D44, 0x3003D47, 0x3003D4A, 0x3003D4D, 0x3003D50, 0x3003D53, 0x3003D56, 0x3003D59, 0x3003D5C, 0x3003D5F, 0x3003D62, 0x3003D65, 0x3003D68, 0x3003D6B, 0x3003D6E, 0x3003D71, 0x3003D74, 0x3003D77, 0x3003D7A, 0x3003D7D, 0x0, 0x3003D80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003D83, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003D86, 0x0, 0x3003D89, 0x0, 0x3003D8C, 0x0, 0x3003D8F, 0x0, 0x3003D92, 0x0, 0x3003D95, 0x0, 0x3003D98, 0x0, 0x3003D9B, 0x0, 0x3003D9E, 0x0, 0x3003DA1, 0x0, 0x3003DA4, 0x0, 0x3003DA7, 0x0, 0x3003DAA, 0x0, 0x3003DAD, 0x0, 0x3003DB0, 0x0, 0x3003DB3, 0x0, 0x3003DB6, 0x0, 0x3003DB9, 0x0, 0x3003DBC, 0x0, 0x3003DBF, 0x0, 0x3003DC2, 0x0, 0x3003DC5, 0x0, 0x3003DC8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003DCB, 0x0, 0x3003DCE, 0x0, 0x3003DD1, 0x0, 0x3003DD4, 0x0, 0x3003DD7, 0x0, 0x3003DDA, 0x0, 0x3003DDD, 0x0, 0x3003DE0, 0x0, 0x3003DE3, 0x0, 0x3003DE6, 0x0, 0x3003DE9, 0x0, 0x3003DEC, 0x0, 0x3003DEF, 0x0, 0x3003DF2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003DF5, 0x0, 0x3003DF8, 0x0, 0x3003DFB, 0x0, 0x3003DFE, 0x0, 0x3003E01, 0x0, 0x3003E04, 0x0, 0x3003E07, 0x0, 0x0, 0x0, 0x3003E0A, 0x0, 0x3003E0D, 0x0, 0x3003E10, 0x0, 0x3003E13, 0x0, 0x3003E16, 0x0, 0x3003E19, 0x0, 0x3003E1C, 0x0, 0x3003E1F, 0x0, 0x3003E22, 0x0, 0x3003E25, 0x0, 0x3003E28, 0x0, 0x3003E2B, 0x0, 0x3003E2E, 0x0, 0x3003E31, 0x0, 0x3003E34, 0x0, 0x3003E37, 0x0, 0x3003E3A, 0x0, 0x3003E3D, 0x0, 0x3003E40, 0x0, 0x3003E43, 0x0, 0x3003E46, 0x0, 0x3003E49, 0x0, 0x3003E4C, 0x0, 0x3003E4F, 0x0, 0x3003E52, 0x0, 0x3003E55, 0x0, 0x3003E58, 0x0, 0x3003E5B, 0x0, 0x3003E5E, 0x0, 0x3003E61, 0x0, 0x3003E64, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003E67, 0x0, 0x3003E6A, 0x0, 0x0, 0x3003E6D, 0x0, 0x3003E70, 0x0, 0x3003E73, 0x0, 0x3003E76, 0x0, 0x3003E79, 0x0, 0x0, 0x0, 0x0, 0x3003E7C, 0x0, 0x0, 0x0, 0x0, 0x3003E7F, 0x0, 0x3003E82, 0x0, 0x0, 0x0, 0x3003E85, 0x0, 0x3003E88, 0x0, 0x3003E8B, 0x0, 0x3003E8E, 0x0, 0x3003E91, 0x0, 0x3003E94, 0x0, 0x3003E97, 0x0, 0x3003E9A, 0x0, 0x3003E9D, 0x0, 0x3003EA0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2003EA3, 0x2003EA5, 0x2003EA7, 0x3003EA9, 0x3003EAC, 0x2003EAF, 0x2003EAF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4003EB1, 0x4003EB5, 0x4003EB9, 0x4003EBD, 0x4003EC1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003EC5, 0x3003EC8, 0x3003ECB, 0x3003ECE, 0x3003ED1, 0x3003ED4, 0x3003ED7, 0x3003EDA, 0x3003EDD, 0x3003EE0, 0x3003EE3, 0x3003EE6, 0x3003EE9, 0x3003EEC, 0x3003EEF, 0x3003EF2, 0x3003EF5, 0x3003EF8, 0x3003EFB, 0x3003EFE, 0x3003F01, 0x3003F04, 0x3003F07, 0x3003F0A, 0x3003F0D, 0x3003F10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4003F13, 0x4003F17, 0x4003F1B, 0x4003F1F, 0x4003F23, 0x4003F27, 0x4003F2B, 0x4003F2F, 0x4003F33, 0x4003F37, 0x4003F3B, 0x4003F3F, 0x4003F43, 0x4003F47, 0x4003F4B, 0x4003F4F, 0x4003F53, 0x4003F57, 0x4003F5B, 0x4003F5F, 0x4003F63, 0x4003F67, 0x4003F6B, 0x4003F6F, 0x4003F73, 0x4003F77, 0x4003F7B, 0x4003F7F, 0x4003F83, 0x4003F87, 0x4003F8B, 0x4003F8F, 0x4003F93, 0x4003F97, 0x4003F9B, 0x4003F9F, 0x4003FA3, 0x4003FA7, 0x4003FAB, 0x4003FAF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4003FB3, 0x4003FB7, 0x4003FBB, 0x4003FBF, 0x4003FC3, 0x4003FC7, 0x4003FCB, 0x4003FCF, 0x4003FD3, 0x4003FD7, 0x4003FDB, 0x4003FDF, 0x4003FE3, 0x4003FE7, 0x4003FEB, 0x4003FEF, 0x4003FF3, 0x4003FF7, 0x4003FFB, 0x4003FFF, 0x4004003, 0x4004007, 0x400400B, 0x400400F, 0x4004013, 0x4004017, 0x400401B, 0x400401F, 0x4004023, 0x4004027, 0x400402B, 0x400402F, }; const uint32_t* UppercaseDataPtr = UppercaseData; const uint32_t LowercaseIndex1[272] = { 0, 128, 256, 384, 360, 360, 360, 360, 360, 360, 512, 360, 360, 360, 360, 640, 768, 896, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, }; const uint32_t* LowercaseIndex1Ptr = LowercaseIndex1; const uint32_t LowercaseIndex2[1024] = { 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x40, 0x0, 0x60, 0x80, 0xA0, 0xC0, 0xE0, 0x100, 0x120, 0x140, 0x160, 0x180, 0x1A0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1C0, 0x1E0, 0x200, 0x220, 0x240, 0x260, 0x280, 0x0, 0x2A0, 0x2C0, 0x2E0, 0x300, 0x320, 0x340, 0x360, 0x380, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3A0, 0x3C0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3E0, 0x400, 0x420, 0x440, 0x460, 0x480, 0x4A0, 0x4C0, 0x4E0, 0x500, 0x520, 0x540, 0x560, 0x580, 0x5A0, 0x5C0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5E0, 0x0, 0x600, 0x620, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x640, 0x660, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x680, 0x6A0, 0x0, 0x6C0, 0x6E0, 0x700, 0x720, 0x740, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x760, 0x780, 0x7A0, 0x0, 0x0, 0x0, 0x0, 0x7C0, 0x7E0, 0x800, 0x820, 0x840, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x860, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x880, 0x8A0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8C0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, }; const uint32_t* LowercaseIndex2Ptr = LowercaseIndex2; const uint32_t LowercaseData[2272] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x100004E, 0x1000636, 0x1000060, 0x10000CC, 0x1000063, 0x100069A, 0x10000F0, 0x1000108, 0x100006F, 0x1000129, 0x100012F, 0x1000135, 0x1000702, 0x100007B, 0x100007E, 0x1000754, 0x1002068, 0x100016B, 0x100017D, 0x1000195, 0x100008D, 0x10007E4, 0x10001C5, 0x100080E, 0x1000099, 0x10001D4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2004033, 0x2004035, 0x2004037, 0x2004039, 0x200403B, 0x200403D, 0x2000247, 0x200403F, 0x2004041, 0x2004043, 0x2004045, 0x2004047, 0x2004049, 0x200404B, 0x200404D, 0x200404F, 0x2001E1E, 0x2004051, 0x2004053, 0x2004055, 0x2004057, 0x2004059, 0x200405B, 0x0, 0x2000294, 0x200405D, 0x200405F, 0x2004061, 0x2004063, 0x2004065, 0x2004067, 0x0, 0x2004069, 0x0, 0x200406B, 0x0, 0x200406D, 0x0, 0x200406F, 0x0, 0x2004071, 0x0, 0x2004073, 0x0, 0x2004075, 0x0, 0x2004077, 0x0, 0x2004079, 0x0, 0x200407B, 0x0, 0x200407D, 0x0, 0x200407F, 0x0, 0x2004081, 0x0, 0x2004083, 0x0, 0x2004085, 0x0, 0x2004087, 0x0, 0x2004089, 0x0, 0x200408B, 0x0, 0x200408D, 0x0, 0x2001EF8, 0x0, 0x200408F, 0x0, 0x2004091, 0x0, 0x2004093, 0x0, 0x2004095, 0x0, 0x3004097, 0x0, 0x200409A, 0x0, 0x200409C, 0x0, 0x200409E, 0x0, 0x0, 0x20040A0, 0x0, 0x20040A2, 0x0, 0x20040A4, 0x0, 0x20040A6, 0x0, 0x20040A8, 0x0, 0x20040AA, 0x0, 0x20040AC, 0x0, 0x20040AE, 0x0, 0x0, 0x2001E00, 0x0, 0x20040B0, 0x0, 0x20040B2, 0x0, 0x20040B4, 0x0, 0x2002CE5, 0x0, 0x20040B6, 0x0, 0x20040B8, 0x0, 0x20040BA, 0x0, 0x20040BC, 0x0, 0x20040BE, 0x0, 0x20040C0, 0x0, 0x20040C2, 0x0, 0x20040C4, 0x0, 0x20040C6, 0x0, 0x20040C8, 0x0, 0x20040CA, 0x0, 0x20040CC, 0x0, 0x20040CE, 0x0, 0x20040D0, 0x0, 0x20040D2, 0x0, 0x20040D4, 0x0, 0x20040D6, 0x0, 0x20040D8, 0x0, 0x20040DA, 0x20040DC, 0x0, 0x20040DE, 0x0, 0x20040E0, 0x0, 0x0, 0x0, 0x20040E2, 0x20040E4, 0x0, 0x20040E6, 0x0, 0x2001E02, 0x20040E8, 0x0, 0x20040EA, 0x20040EC, 0x20040EE, 0x0, 0x0, 0x20040F0, 0x2001DFA, 0x2001DFC, 0x20040F2, 0x0, 0x20040F4, 0x2001D7D, 0x0, 0x2001E28, 0x2001E26, 0x20040F6, 0x0, 0x0, 0x0, 0x2001E0D, 0x2001E3C, 0x0, 0x2001E42, 0x20040F8, 0x0, 0x20040FA, 0x0, 0x20040FC, 0x0, 0x20040FE, 0x2004100, 0x0, 0x2001E48, 0x0, 0x0, 0x2004102, 0x0, 0x2004104, 0x2004106, 0x0, 0x2001E4E, 0x2001E53, 0x2004108, 0x0, 0x200410A, 0x0, 0x200026B, 0x200410C, 0x0, 0x0, 0x0, 0x200410E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2004110, 0x2004110, 0x0, 0x2004112, 0x2004112, 0x0, 0x2004114, 0x2004114, 0x0, 0x2004116, 0x0, 0x2004118, 0x0, 0x200411A, 0x0, 0x200411C, 0x0, 0x200411E, 0x0, 0x2004120, 0x0, 0x2004122, 0x0, 0x2004124, 0x0, 0x0, 0x2004126, 0x0, 0x2004128, 0x0, 0x200412A, 0x0, 0x200412C, 0x0, 0x200412E, 0x0, 0x2004130, 0x0, 0x2004132, 0x0, 0x2004134, 0x0, 0x2004136, 0x0, 0x0, 0x2004138, 0x2004138, 0x0, 0x200413A, 0x0, 0x200413C, 0x200413E, 0x2004140, 0x0, 0x2004142, 0x0, 0x2004144, 0x0, 0x2004146, 0x0, 0x2004148, 0x0, 0x200414A, 0x0, 0x200414C, 0x0, 0x200414E, 0x0, 0x2004150, 0x0, 0x2004152, 0x0, 0x2004154, 0x0, 0x2004156, 0x0, 0x2004158, 0x0, 0x200415A, 0x0, 0x200415C, 0x0, 0x200415E, 0x0, 0x2004160, 0x0, 0x2004162, 0x0, 0x2004164, 0x0, 0x2004166, 0x0, 0x2004168, 0x0, 0x200416A, 0x0, 0x200416C, 0x0, 0x200416E, 0x0, 0x2004170, 0x0, 0x2004172, 0x0, 0x2004174, 0x0, 0x2004176, 0x0, 0x2004178, 0x0, 0x200417A, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x300417C, 0x200417F, 0x0, 0x2004181, 0x3004183, 0x0, 0x0, 0x2004186, 0x0, 0x2004188, 0x2001E4C, 0x2001E55, 0x200418A, 0x0, 0x200418C, 0x0, 0x200418E, 0x0, 0x2004190, 0x0, 0x2004192, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2004194, 0x0, 0x2004196, 0x0, 0x0, 0x0, 0x2004198, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200419A, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200419C, 0x0, 0x200419E, 0x20041A0, 0x20041A2, 0x0, 0x20041A4, 0x0, 0x20041A6, 0x20041A8, 0x0, 0x2000357, 0x2001D89, 0x2001E12, 0x2001E14, 0x200035B, 0x2003369, 0x200035F, 0x2001D8B, 0x2000349, 0x2001D91, 0x200336B, 0x2001D29, 0x200336D, 0x200336F, 0x200036D, 0x2001D8F, 0x2000E17, 0x0, 0x2003371, 0x2003373, 0x2000367, 0x2001D8D, 0x2001E16, 0x2003375, 0x2000375, 0x20041AA, 0x20041AC, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20041AE, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20041B0, 0x0, 0x20041B2, 0x0, 0x200337C, 0x0, 0x20041B4, 0x0, 0x20041B6, 0x0, 0x20041B8, 0x0, 0x20041BA, 0x0, 0x20041BC, 0x0, 0x20041BE, 0x0, 0x20041C0, 0x0, 0x20041C2, 0x0, 0x20041C4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2001D8B, 0x0, 0x0, 0x20041C6, 0x0, 0x20041C8, 0x20041CA, 0x0, 0x0, 0x20041CC, 0x20041CE, 0x20041D0, 0x20041D2, 0x20041D4, 0x20041D6, 0x20041D8, 0x20041DA, 0x20041DC, 0x20003B1, 0x20041DE, 0x20041E0, 0x20041E2, 0x20041E4, 0x20041E6, 0x20041E8, 0x20041EA, 0x20041EC, 0x20041EE, 0x20003D5, 0x20041F0, 0x20041F2, 0x20003AD, 0x20041F4, 0x20003A5, 0x20003CD, 0x20003FD, 0x20003A1, 0x20041F6, 0x20003B5, 0x20041F8, 0x20041FA, 0x2001E18, 0x2000415, 0x20041FC, 0x20041FE, 0x2004200, 0x2004202, 0x20003BD, 0x2004204, 0x2004206, 0x2004208, 0x2000445, 0x200420A, 0x200420C, 0x2002CDC, 0x200044D, 0x2002CDE, 0x2000425, 0x200420E, 0x2004210, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2004212, 0x0, 0x2004214, 0x0, 0x2004216, 0x0, 0x2004218, 0x0, 0x200421A, 0x0, 0x200421C, 0x0, 0x200421E, 0x0, 0x2004220, 0x0, 0x2004222, 0x0, 0x2004224, 0x0, 0x20003C5, 0x0, 0x2004226, 0x0, 0x2004228, 0x0, 0x200422A, 0x0, 0x200422C, 0x0, 0x200422E, 0x0, 0x2004230, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2004232, 0x0, 0x2004234, 0x0, 0x2004236, 0x0, 0x2004238, 0x0, 0x200423A, 0x0, 0x200423C, 0x0, 0x200423E, 0x0, 0x2004240, 0x0, 0x2004242, 0x0, 0x2004244, 0x0, 0x2004246, 0x0, 0x2004248, 0x0, 0x200424A, 0x0, 0x200424C, 0x0, 0x200424E, 0x0, 0x2004250, 0x0, 0x2004252, 0x0, 0x2004254, 0x0, 0x2004256, 0x0, 0x2004258, 0x0, 0x200425A, 0x0, 0x200425C, 0x0, 0x200425E, 0x0, 0x2004260, 0x0, 0x2004262, 0x0, 0x2004264, 0x0, 0x2004266, 0x0, 0x2004268, 0x200426A, 0x0, 0x200426C, 0x0, 0x200426E, 0x0, 0x2004270, 0x0, 0x2004272, 0x0, 0x2004274, 0x0, 0x2004276, 0x0, 0x0, 0x2004278, 0x0, 0x200427A, 0x0, 0x200427C, 0x0, 0x200427E, 0x0, 0x20003ED, 0x0, 0x2004280, 0x0, 0x2004282, 0x0, 0x2004284, 0x0, 0x2004286, 0x0, 0x2004288, 0x0, 0x200428A, 0x0, 0x200428C, 0x0, 0x200041D, 0x0, 0x200428E, 0x0, 0x2004290, 0x0, 0x2004292, 0x0, 0x2004294, 0x0, 0x2004296, 0x0, 0x2004298, 0x0, 0x200429A, 0x0, 0x200429C, 0x0, 0x200429E, 0x0, 0x20042A0, 0x0, 0x20042A2, 0x0, 0x20042A4, 0x0, 0x20042A6, 0x0, 0x20042A8, 0x0, 0x20042AA, 0x0, 0x20042AC, 0x0, 0x20042AE, 0x0, 0x20042B0, 0x0, 0x20042B2, 0x0, 0x20042B4, 0x0, 0x20042B6, 0x0, 0x20042B8, 0x0, 0x20042BA, 0x0, 0x20042BC, 0x0, 0x20042BE, 0x0, 0x20042C0, 0x0, 0x20042C2, 0x0, 0x20042C4, 0x0, 0x20042C6, 0x0, 0x20042C8, 0x0, 0x20042CA, 0x0, 0x20042CC, 0x0, 0x20042CE, 0x0, 0x20042D0, 0x0, 0x20042D2, 0x0, 0x0, 0x20042D4, 0x20042D6, 0x20042D8, 0x20042DA, 0x2001D99, 0x20042DC, 0x20042DE, 0x20042E0, 0x20042E2, 0x20042E4, 0x2002D0A, 0x20042E6, 0x2002D12, 0x20042E8, 0x20042EA, 0x20042EC, 0x20042EE, 0x20042F0, 0x20042F2, 0x2002D00, 0x20042F4, 0x2002D02, 0x20042F6, 0x20042F8, 0x20042FA, 0x20042FC, 0x20042FE, 0x2004300, 0x2004302, 0x2002D0C, 0x2004304, 0x2004306, 0x2004308, 0x2001D9B, 0x200430A, 0x200430C, 0x200430E, 0x2004310, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004312, 0x3004315, 0x3004318, 0x300431B, 0x300431E, 0x3004321, 0x3004324, 0x3004327, 0x300432A, 0x300432D, 0x3004330, 0x3004333, 0x3004336, 0x3004339, 0x300433C, 0x300433F, 0x3004342, 0x3004345, 0x3004348, 0x300434B, 0x300434E, 0x3004351, 0x3004354, 0x3004357, 0x300435A, 0x300435D, 0x3004360, 0x3004363, 0x3004366, 0x3004369, 0x300436C, 0x300436F, 0x3004372, 0x3004375, 0x3004378, 0x300437B, 0x300437E, 0x3004381, 0x0, 0x3004384, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004387, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x300438A, 0x0, 0x300438D, 0x0, 0x3004390, 0x0, 0x3004393, 0x0, 0x3004396, 0x0, 0x3004399, 0x0, 0x300439C, 0x0, 0x300439F, 0x0, 0x30043A2, 0x0, 0x30043A5, 0x0, 0x30043A8, 0x0, 0x30043AB, 0x0, 0x30043AE, 0x0, 0x30043B1, 0x0, 0x30043B4, 0x0, 0x30043B7, 0x0, 0x30043BA, 0x0, 0x30043BD, 0x0, 0x30043C0, 0x0, 0x30043C3, 0x0, 0x30043C6, 0x0, 0x30043C9, 0x0, 0x30043CC, 0x0, 0x30043CF, 0x0, 0x30043D2, 0x0, 0x30043D5, 0x0, 0x30043D8, 0x0, 0x30043DB, 0x0, 0x30043DE, 0x0, 0x30043E1, 0x0, 0x30043E4, 0x0, 0x30043E7, 0x0, 0x30043EA, 0x0, 0x30043ED, 0x0, 0x30043F0, 0x0, 0x30043F3, 0x0, 0x30043F6, 0x0, 0x30043F9, 0x0, 0x30043FC, 0x0, 0x30043FF, 0x0, 0x3004402, 0x0, 0x3004405, 0x0, 0x3004408, 0x0, 0x300440B, 0x0, 0x300440E, 0x0, 0x3004411, 0x0, 0x3004414, 0x0, 0x3004417, 0x0, 0x300441A, 0x0, 0x300441D, 0x0, 0x3004420, 0x0, 0x3004423, 0x0, 0x3004426, 0x0, 0x3004429, 0x0, 0x300442C, 0x0, 0x300442F, 0x0, 0x3004432, 0x0, 0x3004435, 0x0, 0x3004438, 0x0, 0x300443B, 0x0, 0x300443E, 0x0, 0x3004441, 0x0, 0x3004444, 0x0, 0x3004447, 0x0, 0x300444A, 0x0, 0x300444D, 0x0, 0x3004450, 0x0, 0x3004453, 0x0, 0x3004456, 0x0, 0x3004459, 0x0, 0x300445C, 0x0, 0x300445F, 0x0, 0x3004462, 0x0, 0x3004465, 0x0, 0x3004468, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200446B, 0x0, 0x300446D, 0x0, 0x3004470, 0x0, 0x3004473, 0x0, 0x3004476, 0x0, 0x3004479, 0x0, 0x300447C, 0x0, 0x300447F, 0x0, 0x3004482, 0x0, 0x3004485, 0x0, 0x3004488, 0x0, 0x300448B, 0x0, 0x300448E, 0x0, 0x3004491, 0x0, 0x3004494, 0x0, 0x3004497, 0x0, 0x300449A, 0x0, 0x300449D, 0x0, 0x30044A0, 0x0, 0x30044A3, 0x0, 0x30044A6, 0x0, 0x30044A9, 0x0, 0x30044AC, 0x0, 0x30044AF, 0x0, 0x30044B2, 0x0, 0x30044B5, 0x0, 0x30044B8, 0x0, 0x30044BB, 0x0, 0x30044BE, 0x0, 0x30044C1, 0x0, 0x30044C4, 0x0, 0x30044C7, 0x0, 0x30044CA, 0x0, 0x30044CD, 0x0, 0x30044D0, 0x0, 0x30044D3, 0x0, 0x30044D6, 0x0, 0x30044D9, 0x0, 0x30044DC, 0x0, 0x30044DF, 0x0, 0x30044E2, 0x0, 0x30044E5, 0x0, 0x30044E8, 0x0, 0x30044EB, 0x0, 0x30044EE, 0x0, 0x30044F1, 0x0, 0x30044F4, 0x0, 0x30044F7, 0x0, 0x30044FA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30044FD, 0x3004500, 0x3004503, 0x3004506, 0x3004509, 0x300450C, 0x300450F, 0x3004512, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004515, 0x3004518, 0x300451B, 0x300451E, 0x3004521, 0x3004524, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004527, 0x300452A, 0x300452D, 0x3004530, 0x3004533, 0x3004536, 0x3004539, 0x300453C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x300453F, 0x3004542, 0x3004545, 0x3004548, 0x300454B, 0x300454E, 0x3004551, 0x3004554, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004557, 0x300455A, 0x300455D, 0x3004560, 0x3004563, 0x3004566, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004569, 0x0, 0x300456C, 0x0, 0x300456F, 0x0, 0x3004572, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004575, 0x3004578, 0x300457B, 0x300457E, 0x3004581, 0x3004584, 0x3004587, 0x300458A, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x300458D, 0x3004590, 0x3004593, 0x3004596, 0x3004599, 0x300459C, 0x300459F, 0x30045A2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30045A5, 0x30045A8, 0x30045AB, 0x30045AE, 0x30045B1, 0x30045B4, 0x30045B7, 0x30045BA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30045BD, 0x30045C0, 0x30045C3, 0x30045C6, 0x30045C9, 0x30045CC, 0x30045CF, 0x30045D2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30045D5, 0x30045D8, 0x30045DB, 0x30045DE, 0x30045E1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30045E4, 0x30045E7, 0x30045EA, 0x30045ED, 0x30045F0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30045F3, 0x30045F6, 0x30045F9, 0x30045FC, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30045FF, 0x3004602, 0x3004605, 0x3004608, 0x300460B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x300460E, 0x3004611, 0x3004614, 0x3004617, 0x300461A, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000375, 0x0, 0x0, 0x0, 0x100012F, 0x200403D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x300461D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004620, 0x3004623, 0x3004626, 0x3004629, 0x300462C, 0x300462F, 0x3004632, 0x3004635, 0x3004638, 0x300463B, 0x300463E, 0x3004641, 0x3004644, 0x3004647, 0x300464A, 0x300464D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004650, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004653, 0x3004656, 0x3004659, 0x300465C, 0x300465F, 0x3004662, 0x3004665, 0x3004668, 0x300466B, 0x300466E, 0x3004671, 0x3004674, 0x3004677, 0x300467A, 0x300467D, 0x3004680, 0x3004683, 0x3004686, 0x3004689, 0x300468C, 0x300468F, 0x3004692, 0x3004695, 0x3004698, 0x300469B, 0x300469E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30046A1, 0x30046A4, 0x30046A7, 0x30046AA, 0x30046AD, 0x30046B0, 0x30046B3, 0x30046B6, 0x30046B9, 0x30046BC, 0x30046BF, 0x30046C2, 0x30046C5, 0x30046C8, 0x30046CB, 0x30046CE, 0x30046D1, 0x30046D4, 0x30046D7, 0x30046DA, 0x30046DD, 0x30046E0, 0x30046E3, 0x30046E6, 0x30046E9, 0x30046EC, 0x30046EF, 0x30046F2, 0x30046F5, 0x30046F8, 0x30046FB, 0x30046FE, 0x3004701, 0x3004704, 0x3004707, 0x300470A, 0x300470D, 0x3004710, 0x3004713, 0x3004716, 0x3004719, 0x300471C, 0x300471F, 0x3004722, 0x3004725, 0x3004728, 0x300472B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x300472E, 0x0, 0x2002CED, 0x3004731, 0x2004734, 0x0, 0x0, 0x3004736, 0x0, 0x3004739, 0x0, 0x300473C, 0x0, 0x2001DF5, 0x2001E38, 0x2001DF3, 0x2001E1A, 0x0, 0x300473F, 0x0, 0x0, 0x3004742, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2004745, 0x2004747, 0x3004749, 0x0, 0x300474C, 0x0, 0x300474F, 0x0, 0x3004752, 0x0, 0x3004755, 0x0, 0x3004758, 0x0, 0x300475B, 0x0, 0x300475E, 0x0, 0x3004761, 0x0, 0x3004764, 0x0, 0x3004767, 0x0, 0x300476A, 0x0, 0x300476D, 0x0, 0x3004770, 0x0, 0x3004773, 0x0, 0x3004776, 0x0, 0x3004779, 0x0, 0x300477C, 0x0, 0x300477F, 0x0, 0x3004782, 0x0, 0x3004785, 0x0, 0x3004788, 0x0, 0x300478B, 0x0, 0x300478E, 0x0, 0x3004791, 0x0, 0x3004794, 0x0, 0x3004797, 0x0, 0x300479A, 0x0, 0x300479D, 0x0, 0x30047A0, 0x0, 0x30047A3, 0x0, 0x30047A6, 0x0, 0x30047A9, 0x0, 0x30047AC, 0x0, 0x30047AF, 0x0, 0x30047B2, 0x0, 0x30047B5, 0x0, 0x30047B8, 0x0, 0x30047BB, 0x0, 0x30047BE, 0x0, 0x30047C1, 0x0, 0x30047C4, 0x0, 0x30047C7, 0x0, 0x30047CA, 0x0, 0x30047CD, 0x0, 0x30047D0, 0x0, 0x30047D3, 0x0, 0x30047D6, 0x0, 0x30047D9, 0x0, 0x30047DC, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30047DF, 0x0, 0x30047E2, 0x0, 0x0, 0x0, 0x0, 0x30047E5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30047E8, 0x0, 0x30047EB, 0x0, 0x30047EE, 0x0, 0x30047F1, 0x0, 0x30047F4, 0x0, 0x30047F7, 0x0, 0x30047FA, 0x0, 0x30047FD, 0x0, 0x3004800, 0x0, 0x3004803, 0x0, 0x3004806, 0x0, 0x3004809, 0x0, 0x300480C, 0x0, 0x300480F, 0x0, 0x3004812, 0x0, 0x3004815, 0x0, 0x3004818, 0x0, 0x300481B, 0x0, 0x300481E, 0x0, 0x3004821, 0x0, 0x3004824, 0x0, 0x3004827, 0x0, 0x300482A, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x300482D, 0x0, 0x3004830, 0x0, 0x3004833, 0x0, 0x3004836, 0x0, 0x3004839, 0x0, 0x300483C, 0x0, 0x300483F, 0x0, 0x3004842, 0x0, 0x3004845, 0x0, 0x3004848, 0x0, 0x300484B, 0x0, 0x300484E, 0x0, 0x3004851, 0x0, 0x3004854, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004857, 0x0, 0x300485A, 0x0, 0x3002CE7, 0x0, 0x300485D, 0x0, 0x3004860, 0x0, 0x3004863, 0x0, 0x3004866, 0x0, 0x0, 0x0, 0x3004869, 0x0, 0x300486C, 0x0, 0x300486F, 0x0, 0x3004872, 0x0, 0x3004875, 0x0, 0x3004878, 0x0, 0x300487B, 0x0, 0x300487E, 0x0, 0x3004881, 0x0, 0x3004884, 0x0, 0x3004887, 0x0, 0x300488A, 0x0, 0x300488D, 0x0, 0x3004890, 0x0, 0x3004893, 0x0, 0x3004896, 0x0, 0x3004899, 0x0, 0x300489C, 0x0, 0x300489F, 0x0, 0x30048A2, 0x0, 0x30048A5, 0x0, 0x30048A8, 0x0, 0x30048AB, 0x0, 0x30048AE, 0x0, 0x30048B1, 0x0, 0x30048B4, 0x0, 0x30048B7, 0x0, 0x30048BA, 0x0, 0x30048BD, 0x0, 0x30048C0, 0x0, 0x3002CE0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30048C3, 0x0, 0x30048C6, 0x0, 0x30048C9, 0x30048CC, 0x0, 0x30048CF, 0x0, 0x30048D2, 0x0, 0x30048D5, 0x0, 0x30048D8, 0x0, 0x0, 0x0, 0x0, 0x30048DB, 0x0, 0x2001E24, 0x0, 0x0, 0x30048DE, 0x0, 0x30048E1, 0x0, 0x0, 0x0, 0x30048E4, 0x0, 0x30048E7, 0x0, 0x30048EA, 0x0, 0x30048ED, 0x0, 0x30048F0, 0x0, 0x30048F3, 0x0, 0x30048F6, 0x0, 0x30048F9, 0x0, 0x30048FC, 0x0, 0x30048FF, 0x0, 0x2001D63, 0x2001DFE, 0x2001E22, 0x2004902, 0x0, 0x0, 0x2004904, 0x2004906, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004908, 0x300490B, 0x300490E, 0x3004911, 0x3004914, 0x3004917, 0x300491A, 0x300491D, 0x3004920, 0x3004923, 0x3004926, 0x3004929, 0x300492C, 0x300492F, 0x3004932, 0x3004935, 0x3004938, 0x300493B, 0x300493E, 0x3004941, 0x3004944, 0x3004947, 0x300494A, 0x300494D, 0x3004950, 0x3004953, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4004956, 0x400495A, 0x400495E, 0x4004962, 0x4004966, 0x400496A, 0x400496E, 0x4004972, 0x4004976, 0x400497A, 0x400497E, 0x4004982, 0x4004986, 0x400498A, 0x400498E, 0x4004992, 0x4004996, 0x400499A, 0x400499E, 0x40049A2, 0x40049A6, 0x40049AA, 0x40049AE, 0x40049B2, 0x40049B6, 0x40049BA, 0x40049BE, 0x40049C2, 0x40049C6, 0x40049CA, 0x40049CE, 0x40049D2, 0x40049D6, 0x40049DA, 0x40049DE, 0x40049E2, 0x40049E6, 0x40049EA, 0x40049EE, 0x40049F2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40049F6, 0x40049FA, 0x40049FE, 0x4004A02, 0x4004A06, 0x4004A0A, 0x4004A0E, 0x4004A12, 0x4004A16, 0x4004A1A, 0x4004A1E, 0x4004A22, 0x4004A26, 0x4004A2A, 0x4004A2E, 0x4004A32, 0x4004A36, 0x4004A3A, 0x4004A3E, 0x4004A42, 0x4004A46, 0x4004A4A, 0x4004A4E, 0x4004A52, 0x4004A56, 0x4004A5A, 0x4004A5E, 0x4004A62, 0x4004A66, 0x4004A6A, 0x4004A6E, 0x4004A72, }; const uint32_t* LowercaseDataPtr = LowercaseData; const uint32_t TitlecaseIndex1[272] = { 0, 128, 256, 45, 45, 45, 45, 45, 45, 45, 384, 45, 45, 45, 45, 512, 640, 768, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, }; const uint32_t* TitlecaseIndex1Ptr = TitlecaseIndex1; const uint32_t TitlecaseIndex2[896] = { 0x0, 0x0, 0x0, 0x20, 0x0, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0, 0x100, 0x120, 0x140, 0x160, 0x180, 0x1A0, 0x1C0, 0x1E0, 0x200, 0x220, 0x0, 0x0, 0x0, 0x0, 0x0, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, 0x0, 0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0x400, 0x0, 0x420, 0x440, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x460, 0x0, 0x0, 0x0, 0x0, 0x480, 0x4A0, 0x4C0, 0x4E0, 0x500, 0x520, 0x540, 0x560, 0x580, 0x5A0, 0x5C0, 0x5E0, 0x600, 0x620, 0x640, 0x660, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x680, 0x6A0, 0x6C0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6E0, 0x700, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x720, 0x740, 0x760, 0x780, 0x7A0, 0x7C0, 0x7E0, 0x800, 0x820, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x840, 0x860, 0x880, 0x0, 0x0, 0x0, 0x0, 0x8A0, 0x8C0, 0x8E0, 0x900, 0x920, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x940, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x960, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x980, 0x9A0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9C0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, }; const uint32_t* TitlecaseIndex2Ptr = TitlecaseIndex2; const uint32_t TitlecaseData[2528] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000000, 0x1000633, 0x1000012, 0x10000C9, 0x1000015, 0x1000697, 0x10000ED, 0x1000105, 0x1000021, 0x1000126, 0x100012C, 0x1000132, 0x10006FF, 0x100002D, 0x1000030, 0x1000751, 0x1001EFC, 0x1000168, 0x100017A, 0x1000192, 0x100003F, 0x10007E1, 0x10001C2, 0x100080B, 0x100004B, 0x10001D1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2003358, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2004A76, 0x20034B3, 0x20034B5, 0x20034B7, 0x20034B9, 0x20034BB, 0x20034BD, 0x2000243, 0x20034BF, 0x20034C1, 0x20034C3, 0x20034C5, 0x20034C7, 0x20034C9, 0x20034CB, 0x20034CD, 0x20034CF, 0x20034D1, 0x20034D3, 0x20034D5, 0x20034D7, 0x20034D9, 0x20034DB, 0x20034DD, 0x0, 0x2000290, 0x20034DF, 0x20034E1, 0x20034E3, 0x20034E5, 0x20034E7, 0x20034E9, 0x20034EB, 0x0, 0x20034ED, 0x0, 0x20034EF, 0x0, 0x20034F1, 0x0, 0x20034F3, 0x0, 0x20034F5, 0x0, 0x20034F7, 0x0, 0x20034F9, 0x0, 0x20034FB, 0x0, 0x20034FD, 0x0, 0x20034FF, 0x0, 0x2003501, 0x0, 0x2003503, 0x0, 0x2003505, 0x0, 0x2003507, 0x0, 0x2003509, 0x0, 0x200350B, 0x0, 0x200350D, 0x0, 0x200350F, 0x0, 0x2003511, 0x0, 0x2002CE3, 0x0, 0x2003513, 0x0, 0x2003515, 0x0, 0x2003517, 0x0, 0x2003519, 0x0, 0x1000021, 0x0, 0x200351B, 0x0, 0x200351D, 0x0, 0x200351F, 0x0, 0x0, 0x2003521, 0x0, 0x2003523, 0x0, 0x2003525, 0x0, 0x2003527, 0x0, 0x2003529, 0x0, 0x200352B, 0x0, 0x200352D, 0x0, 0x200352F, 0x3003531, 0x0, 0x2003534, 0x0, 0x2003536, 0x0, 0x2003538, 0x0, 0x200353A, 0x0, 0x200353C, 0x0, 0x200353E, 0x0, 0x2003540, 0x0, 0x2003542, 0x0, 0x2003544, 0x0, 0x2003546, 0x0, 0x2003548, 0x0, 0x200354A, 0x0, 0x200354C, 0x0, 0x200354E, 0x0, 0x2003550, 0x0, 0x2003552, 0x0, 0x2003554, 0x0, 0x2003556, 0x0, 0x2003558, 0x0, 0x200355A, 0x0, 0x200355C, 0x0, 0x200355E, 0x0, 0x2003560, 0x0, 0x0, 0x2003562, 0x0, 0x2003564, 0x0, 0x2003566, 0x100017A, 0x2003568, 0x0, 0x0, 0x200356A, 0x0, 0x200356C, 0x0, 0x0, 0x200356E, 0x0, 0x0, 0x0, 0x2003570, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2003572, 0x0, 0x0, 0x2003574, 0x0, 0x0, 0x0, 0x2003576, 0x2003578, 0x0, 0x0, 0x0, 0x200357A, 0x0, 0x0, 0x200357C, 0x0, 0x200357E, 0x0, 0x2003580, 0x0, 0x0, 0x2003582, 0x0, 0x0, 0x0, 0x0, 0x2003584, 0x0, 0x0, 0x2003586, 0x0, 0x0, 0x0, 0x2003588, 0x0, 0x200358A, 0x0, 0x0, 0x200358C, 0x0, 0x0, 0x0, 0x200358E, 0x0, 0x2003590, 0x0, 0x0, 0x0, 0x0, 0x2004A78, 0x0, 0x2004A78, 0x2004A7A, 0x0, 0x2004A7A, 0x2004A7C, 0x0, 0x2004A7C, 0x0, 0x2003598, 0x0, 0x200359A, 0x0, 0x200359C, 0x0, 0x200359E, 0x0, 0x20035A0, 0x0, 0x20035A2, 0x0, 0x20035A4, 0x0, 0x20035A6, 0x2001DEF, 0x0, 0x20035A8, 0x0, 0x20035AA, 0x0, 0x20035AC, 0x0, 0x20035AE, 0x0, 0x20035B0, 0x0, 0x20035B2, 0x0, 0x20035B4, 0x0, 0x20035B6, 0x0, 0x20035B8, 0x30035BA, 0x2004A7E, 0x0, 0x2004A7E, 0x0, 0x20035BF, 0x0, 0x0, 0x0, 0x20035C1, 0x0, 0x20035C3, 0x0, 0x20035C5, 0x0, 0x20035C7, 0x0, 0x20035C9, 0x0, 0x20035CB, 0x0, 0x20035CD, 0x0, 0x20035CF, 0x0, 0x20035D1, 0x0, 0x20035D3, 0x0, 0x20035D5, 0x0, 0x20035D7, 0x0, 0x20035D9, 0x0, 0x20035DB, 0x0, 0x20035DD, 0x0, 0x20035DF, 0x0, 0x20035E1, 0x0, 0x20035E3, 0x0, 0x20035E5, 0x0, 0x20035E7, 0x0, 0x0, 0x0, 0x2001DF1, 0x0, 0x20035E9, 0x0, 0x20035EB, 0x0, 0x20035ED, 0x0, 0x20035EF, 0x0, 0x20035F1, 0x0, 0x20035F3, 0x0, 0x20035F5, 0x0, 0x20035F7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20035F9, 0x0, 0x0, 0x30035FB, 0x30035FE, 0x0, 0x2003601, 0x0, 0x0, 0x0, 0x0, 0x2003603, 0x0, 0x2003605, 0x0, 0x2003607, 0x0, 0x2003609, 0x0, 0x200360B, 0x300360D, 0x3003610, 0x3003613, 0x2003616, 0x2003618, 0x0, 0x200361A, 0x200361C, 0x0, 0x200361E, 0x0, 0x2001EF3, 0x3003620, 0x0, 0x0, 0x0, 0x2003623, 0x3003625, 0x0, 0x2003628, 0x0, 0x300362A, 0x300362D, 0x0, 0x2003630, 0x2003632, 0x0, 0x3003634, 0x3003637, 0x0, 0x0, 0x200363A, 0x0, 0x300363C, 0x200363F, 0x0, 0x0, 0x2003641, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003643, 0x0, 0x0, 0x2003646, 0x0, 0x0, 0x2003648, 0x0, 0x0, 0x0, 0x300364A, 0x200364D, 0x200364F, 0x2003651, 0x2003653, 0x2003655, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000267, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003657, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000339, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200365A, 0x0, 0x200365C, 0x0, 0x0, 0x0, 0x200365E, 0x0, 0x0, 0x0, 0x2003660, 0x2003662, 0x2003664, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6003666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200366C, 0x200366E, 0x2003670, 0x2003672, 0x6003674, 0x200032B, 0x200334E, 0x2001F07, 0x2003350, 0x2000331, 0x2003352, 0x2000335, 0x2001D95, 0x2000339, 0x2003354, 0x2003356, 0x2003358, 0x200335A, 0x200335C, 0x200033D, 0x2001F09, 0x2000E35, 0x2001D97, 0x2001D97, 0x200335E, 0x2000341, 0x2003360, 0x2003362, 0x2003364, 0x2000345, 0x200367A, 0x200367C, 0x200367E, 0x2003680, 0x2003682, 0x0, 0x200334E, 0x2001D95, 0x0, 0x0, 0x0, 0x2003360, 0x2001F09, 0x2003684, 0x0, 0x2003686, 0x0, 0x2003688, 0x0, 0x200337A, 0x0, 0x200368A, 0x0, 0x200368C, 0x0, 0x200368E, 0x0, 0x2003690, 0x0, 0x2003692, 0x0, 0x2003694, 0x0, 0x2003696, 0x0, 0x2003698, 0x0, 0x200369A, 0x2003354, 0x2000E35, 0x200369C, 0x200369E, 0x0, 0x2000331, 0x0, 0x0, 0x20036A0, 0x0, 0x0, 0x20036A2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20003D1, 0x20036A4, 0x20036A6, 0x2000389, 0x20036A8, 0x2000381, 0x20003C9, 0x20003F9, 0x2000395, 0x20036AA, 0x2000391, 0x20036AC, 0x20036AE, 0x20036B0, 0x2000411, 0x20036B2, 0x20036B4, 0x20036B6, 0x20036B8, 0x2000399, 0x20036BA, 0x20036BC, 0x20036BE, 0x2000441, 0x20036C0, 0x20036C2, 0x20036C4, 0x2000449, 0x20036C6, 0x2000421, 0x20036C8, 0x20036CA, 0x20036CC, 0x20036CE, 0x20036D0, 0x20036D2, 0x20036D4, 0x20036D6, 0x200038D, 0x20036D8, 0x20036DA, 0x20036DC, 0x20036DE, 0x20036E0, 0x20036E2, 0x20036E4, 0x20036E6, 0x20036E8, 0x0, 0x20036EA, 0x0, 0x20036EC, 0x0, 0x20036EE, 0x0, 0x20036F0, 0x0, 0x20036F2, 0x0, 0x20036F4, 0x0, 0x20036F6, 0x0, 0x20036F8, 0x0, 0x20036FA, 0x0, 0x20036FC, 0x0, 0x20003C1, 0x0, 0x20036FE, 0x0, 0x2003700, 0x0, 0x2003702, 0x0, 0x2003704, 0x0, 0x2003706, 0x0, 0x2003708, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200370A, 0x0, 0x200370C, 0x0, 0x200370E, 0x0, 0x2003710, 0x0, 0x2003712, 0x0, 0x2003714, 0x0, 0x2003716, 0x0, 0x2003718, 0x0, 0x200371A, 0x0, 0x200371C, 0x0, 0x200371E, 0x0, 0x2003720, 0x0, 0x2003722, 0x0, 0x2003724, 0x0, 0x2003726, 0x0, 0x2003728, 0x0, 0x200372A, 0x0, 0x200372C, 0x0, 0x200372E, 0x0, 0x2003730, 0x0, 0x2003732, 0x0, 0x2003734, 0x0, 0x2003736, 0x0, 0x2003738, 0x0, 0x200373A, 0x0, 0x200373C, 0x0, 0x200373E, 0x0, 0x0, 0x2003740, 0x0, 0x2003742, 0x0, 0x2003744, 0x0, 0x2003746, 0x0, 0x2003748, 0x0, 0x200374A, 0x0, 0x200374C, 0x200374E, 0x0, 0x2003750, 0x0, 0x2003752, 0x0, 0x2003754, 0x0, 0x2003756, 0x0, 0x20003E9, 0x0, 0x2003758, 0x0, 0x200375A, 0x0, 0x200375C, 0x0, 0x200375E, 0x0, 0x2003760, 0x0, 0x2003762, 0x0, 0x2003764, 0x0, 0x2000419, 0x0, 0x2003766, 0x0, 0x2003768, 0x0, 0x200376A, 0x0, 0x200376C, 0x0, 0x200376E, 0x0, 0x2003770, 0x0, 0x2003772, 0x0, 0x2003774, 0x0, 0x2003776, 0x0, 0x2003778, 0x0, 0x200377A, 0x0, 0x200377C, 0x0, 0x200377E, 0x0, 0x2003780, 0x0, 0x2003782, 0x0, 0x2003784, 0x0, 0x2003786, 0x0, 0x2003788, 0x0, 0x200378A, 0x0, 0x200378C, 0x0, 0x200378E, 0x0, 0x2003790, 0x0, 0x2003792, 0x0, 0x2003794, 0x0, 0x2003796, 0x0, 0x2003798, 0x0, 0x200379A, 0x0, 0x200379C, 0x0, 0x200379E, 0x0, 0x20037A0, 0x0, 0x20037A2, 0x0, 0x20037A4, 0x0, 0x20037A6, 0x0, 0x20037A8, 0x0, 0x20037AA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20037AC, 0x20037AE, 0x20037B0, 0x20037B2, 0x20037B4, 0x20037B6, 0x20037B8, 0x20037BA, 0x20037BC, 0x20037BE, 0x20037C0, 0x20037C2, 0x20037C4, 0x20037C6, 0x20037C8, 0x20037CA, 0x20037CC, 0x20037CE, 0x20037D0, 0x20037D2, 0x20037D4, 0x20037D6, 0x20037D8, 0x20037DA, 0x20037DC, 0x20037DE, 0x20037E0, 0x20037E2, 0x20037E4, 0x20037E6, 0x20037E8, 0x20037EA, 0x20037EC, 0x20037EE, 0x20037F0, 0x20037F2, 0x20037F4, 0x20037F6, 0x4004A80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30037FC, 0x0, 0x0, 0x0, 0x30037FF, 0x0, 0x0, 0x0, 0x3003802, 0x0, 0x3003805, 0x0, 0x3003808, 0x0, 0x300380B, 0x0, 0x300380E, 0x0, 0x3003811, 0x0, 0x3003814, 0x0, 0x3003817, 0x0, 0x300381A, 0x0, 0x300381D, 0x0, 0x3003820, 0x0, 0x3003823, 0x0, 0x3003826, 0x0, 0x3003829, 0x0, 0x300382C, 0x0, 0x300382F, 0x0, 0x3003832, 0x0, 0x3003835, 0x0, 0x3003838, 0x0, 0x300383B, 0x0, 0x300383E, 0x0, 0x3003841, 0x0, 0x3003844, 0x0, 0x3003847, 0x0, 0x300384A, 0x0, 0x300384D, 0x0, 0x3003850, 0x0, 0x3003853, 0x0, 0x3003856, 0x0, 0x3003859, 0x0, 0x300385C, 0x0, 0x300385F, 0x0, 0x3003862, 0x0, 0x3003865, 0x0, 0x3003868, 0x0, 0x300386B, 0x0, 0x300386E, 0x0, 0x3003871, 0x0, 0x3003874, 0x0, 0x3003877, 0x0, 0x300387A, 0x0, 0x300387D, 0x0, 0x3003880, 0x0, 0x3003883, 0x0, 0x3003886, 0x0, 0x3003889, 0x0, 0x300388C, 0x0, 0x300388F, 0x0, 0x3003892, 0x0, 0x3003895, 0x0, 0x3003898, 0x0, 0x300389B, 0x0, 0x300389E, 0x0, 0x30038A1, 0x0, 0x30038A4, 0x0, 0x30038A7, 0x0, 0x30038AA, 0x0, 0x30038AD, 0x0, 0x30038B0, 0x0, 0x30038B3, 0x0, 0x30038B6, 0x0, 0x30038B9, 0x0, 0x30038BC, 0x0, 0x30038BF, 0x0, 0x30038C2, 0x0, 0x30038C5, 0x0, 0x30038C8, 0x0, 0x30038CB, 0x0, 0x30038CE, 0x0, 0x30038D1, 0x0, 0x30038D4, 0x0, 0x30038D7, 0x0, 0x30038DA, 0x0, 0x30038DD, 0x0, 0x30038E0, 0x30038E3, 0x30038E6, 0x30038E9, 0x30038EC, 0x30038EF, 0x3003892, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30038F2, 0x0, 0x30038F5, 0x0, 0x30038F8, 0x0, 0x30038FB, 0x0, 0x30038FE, 0x0, 0x3003901, 0x0, 0x3003904, 0x0, 0x3003907, 0x0, 0x300390A, 0x0, 0x300390D, 0x0, 0x3003910, 0x0, 0x3003913, 0x0, 0x3003916, 0x0, 0x3003919, 0x0, 0x300391C, 0x0, 0x300391F, 0x0, 0x3003922, 0x0, 0x3003925, 0x0, 0x3003928, 0x0, 0x300392B, 0x0, 0x300392E, 0x0, 0x3003931, 0x0, 0x3003934, 0x0, 0x3003937, 0x0, 0x300393A, 0x0, 0x300393D, 0x0, 0x3003940, 0x0, 0x3003943, 0x0, 0x3003946, 0x0, 0x3003949, 0x0, 0x300394C, 0x0, 0x300394F, 0x0, 0x3003952, 0x0, 0x3003955, 0x0, 0x3003958, 0x0, 0x300395B, 0x0, 0x300395E, 0x0, 0x3003961, 0x0, 0x3003964, 0x0, 0x3003967, 0x0, 0x300396A, 0x0, 0x300396D, 0x0, 0x3003970, 0x0, 0x3003973, 0x0, 0x3003976, 0x0, 0x3003979, 0x0, 0x300397C, 0x0, 0x300397F, 0x3003982, 0x3003985, 0x3003988, 0x300398B, 0x300398E, 0x3003991, 0x3003994, 0x3003997, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x300399A, 0x300399D, 0x30039A0, 0x30039A3, 0x30039A6, 0x30039A9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30039AC, 0x30039AF, 0x30039B2, 0x30039B5, 0x30039B8, 0x30039BB, 0x30039BE, 0x30039C1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30039C4, 0x30039C7, 0x30039CA, 0x30039CD, 0x30039D0, 0x30039D3, 0x30039D6, 0x30039D9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30039DC, 0x30039DF, 0x30039E2, 0x30039E5, 0x30039E8, 0x30039EB, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40039EE, 0x30039F2, 0x60039F5, 0x30039FB, 0x60039FE, 0x3003A04, 0x6003A07, 0x3003A0D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003A10, 0x3003A13, 0x3003A16, 0x3003A19, 0x3003A1C, 0x3003A1F, 0x3003A22, 0x3003A25, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003A28, 0x3003A2B, 0x3003A2E, 0x3003A31, 0x3003A34, 0x3003A37, 0x3003A3A, 0x3003A3D, 0x3003A40, 0x3003A43, 0x3003A46, 0x3003A49, 0x3003A4C, 0x3003A4F, 0x0, 0x0, 0x3004A84, 0x3004A87, 0x3004A8A, 0x3004A8D, 0x3004A90, 0x3004A93, 0x3004A96, 0x3004A99, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004A9C, 0x3004A9F, 0x3004AA2, 0x3004AA5, 0x3004AA8, 0x3004AAB, 0x3004AAE, 0x3004AB1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004AB4, 0x3004AB7, 0x3004ABA, 0x3004ABD, 0x3004AC0, 0x3004AC3, 0x3004AC6, 0x3004AC9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003ACA, 0x3003ACD, 0x5004ACC, 0x3004AD1, 0x4004AD4, 0x0, 0x4003ADD, 0x6004AD8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000339, 0x0, 0x0, 0x0, 0x5004ADE, 0x3004AE3, 0x4004AE6, 0x0, 0x4003AF4, 0x6004AEA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003AFE, 0x3003B01, 0x6003B04, 0x6003666, 0x0, 0x0, 0x4003B0A, 0x6003B0E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003B14, 0x3003B17, 0x6003B1A, 0x6003674, 0x4003B20, 0x3003B24, 0x4003B27, 0x6003B2B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5004AF0, 0x3004AF5, 0x4004AF8, 0x0, 0x4003B3E, 0x6004AFC, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003B48, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003B4B, 0x3003B4E, 0x3003B51, 0x3003B54, 0x3003B57, 0x3003B5A, 0x3003B5D, 0x3003B60, 0x3003B63, 0x3003B66, 0x3003B69, 0x3003B6C, 0x3003B6F, 0x3003B72, 0x3003B75, 0x3003B78, 0x0, 0x0, 0x0, 0x0, 0x3003B7B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003B7E, 0x3003B81, 0x3003B84, 0x3003B87, 0x3003B8A, 0x3003B8D, 0x3003B90, 0x3003B93, 0x3003B96, 0x3003B99, 0x3003B9C, 0x3003B9F, 0x3003BA2, 0x3003BA5, 0x3003BA8, 0x3003BAB, 0x3003BAE, 0x3003BB1, 0x3003BB4, 0x3003BB7, 0x3003BBA, 0x3003BBD, 0x3003BC0, 0x3003BC3, 0x3003BC6, 0x3003BC9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003BCC, 0x3003BCF, 0x3003BD2, 0x3003BD5, 0x3003BD8, 0x3003BDB, 0x3003BDE, 0x3003BE1, 0x3003BE4, 0x3003BE7, 0x3003BEA, 0x3003BED, 0x3003BF0, 0x3003BF3, 0x3003BF6, 0x3003BF9, 0x3003BFC, 0x3003BFF, 0x3003C02, 0x3003C05, 0x3003C08, 0x3003C0B, 0x3003C0E, 0x3003C11, 0x3003C14, 0x3003C17, 0x3003C1A, 0x3003C1D, 0x3003C20, 0x3003C23, 0x3003C26, 0x3003C29, 0x3003C2C, 0x3003C2F, 0x3003C32, 0x3003C35, 0x3003C38, 0x3003C3B, 0x3003C3E, 0x3003C41, 0x3003C44, 0x3003C47, 0x3003C4A, 0x3003C4D, 0x3003C50, 0x3003C53, 0x3003C56, 0x0, 0x0, 0x3003C59, 0x0, 0x0, 0x0, 0x2003C5C, 0x2003C5E, 0x0, 0x3003C60, 0x0, 0x3003C63, 0x0, 0x3003C66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003C69, 0x0, 0x0, 0x3003C6C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003C6F, 0x0, 0x3003C72, 0x0, 0x3003C75, 0x0, 0x3003C78, 0x0, 0x3003C7B, 0x0, 0x3003C7E, 0x0, 0x3003C81, 0x0, 0x3003C84, 0x0, 0x3003C87, 0x0, 0x3003C8A, 0x0, 0x3003C8D, 0x0, 0x3003C90, 0x0, 0x3003C93, 0x0, 0x3003C96, 0x0, 0x3003C99, 0x0, 0x3003C9C, 0x0, 0x3003C9F, 0x0, 0x3003CA2, 0x0, 0x3003CA5, 0x0, 0x3003CA8, 0x0, 0x3003CAB, 0x0, 0x3003CAE, 0x0, 0x3003CB1, 0x0, 0x3003CB4, 0x0, 0x3003CB7, 0x0, 0x3003CBA, 0x0, 0x3003CBD, 0x0, 0x3003CC0, 0x0, 0x3003CC3, 0x0, 0x3003CC6, 0x0, 0x3003CC9, 0x0, 0x3003CCC, 0x0, 0x3003CCF, 0x0, 0x3003CD2, 0x0, 0x3003CD5, 0x0, 0x3003CD8, 0x0, 0x3003CDB, 0x0, 0x3003CDE, 0x0, 0x3003CE1, 0x0, 0x3003CE4, 0x0, 0x3003CE7, 0x0, 0x3003CEA, 0x0, 0x3003CED, 0x0, 0x3003CF0, 0x0, 0x3003CF3, 0x0, 0x3003CF6, 0x0, 0x3003CF9, 0x0, 0x3003CFC, 0x0, 0x3003CFF, 0x0, 0x3003D02, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003D05, 0x0, 0x3003D08, 0x0, 0x0, 0x0, 0x0, 0x3003D0B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003D0E, 0x3003D11, 0x3003D14, 0x3003D17, 0x3003D1A, 0x3003D1D, 0x3003D20, 0x3003D23, 0x3003D26, 0x3003D29, 0x3003D2C, 0x3003D2F, 0x3003D32, 0x3003D35, 0x3003D38, 0x3003D3B, 0x3003D3E, 0x3003D41, 0x3003D44, 0x3003D47, 0x3003D4A, 0x3003D4D, 0x3003D50, 0x3003D53, 0x3003D56, 0x3003D59, 0x3003D5C, 0x3003D5F, 0x3003D62, 0x3003D65, 0x3003D68, 0x3003D6B, 0x3003D6E, 0x3003D71, 0x3003D74, 0x3003D77, 0x3003D7A, 0x3003D7D, 0x0, 0x3003D80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003D83, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003D86, 0x0, 0x3003D89, 0x0, 0x3003D8C, 0x0, 0x3003D8F, 0x0, 0x3003D92, 0x0, 0x3003D95, 0x0, 0x3003D98, 0x0, 0x3003D9B, 0x0, 0x3003D9E, 0x0, 0x3003DA1, 0x0, 0x3003DA4, 0x0, 0x3003DA7, 0x0, 0x3003DAA, 0x0, 0x3003DAD, 0x0, 0x3003DB0, 0x0, 0x3003DB3, 0x0, 0x3003DB6, 0x0, 0x3003DB9, 0x0, 0x3003DBC, 0x0, 0x3003DBF, 0x0, 0x3003DC2, 0x0, 0x3003DC5, 0x0, 0x3003DC8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003DCB, 0x0, 0x3003DCE, 0x0, 0x3003DD1, 0x0, 0x3003DD4, 0x0, 0x3003DD7, 0x0, 0x3003DDA, 0x0, 0x3003DDD, 0x0, 0x3003DE0, 0x0, 0x3003DE3, 0x0, 0x3003DE6, 0x0, 0x3003DE9, 0x0, 0x3003DEC, 0x0, 0x3003DEF, 0x0, 0x3003DF2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003DF5, 0x0, 0x3003DF8, 0x0, 0x3003DFB, 0x0, 0x3003DFE, 0x0, 0x3003E01, 0x0, 0x3003E04, 0x0, 0x3003E07, 0x0, 0x0, 0x0, 0x3003E0A, 0x0, 0x3003E0D, 0x0, 0x3003E10, 0x0, 0x3003E13, 0x0, 0x3003E16, 0x0, 0x3003E19, 0x0, 0x3003E1C, 0x0, 0x3003E1F, 0x0, 0x3003E22, 0x0, 0x3003E25, 0x0, 0x3003E28, 0x0, 0x3003E2B, 0x0, 0x3003E2E, 0x0, 0x3003E31, 0x0, 0x3003E34, 0x0, 0x3003E37, 0x0, 0x3003E3A, 0x0, 0x3003E3D, 0x0, 0x3003E40, 0x0, 0x3003E43, 0x0, 0x3003E46, 0x0, 0x3003E49, 0x0, 0x3003E4C, 0x0, 0x3003E4F, 0x0, 0x3003E52, 0x0, 0x3003E55, 0x0, 0x3003E58, 0x0, 0x3003E5B, 0x0, 0x3003E5E, 0x0, 0x3003E61, 0x0, 0x3003E64, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003E67, 0x0, 0x3003E6A, 0x0, 0x0, 0x3003E6D, 0x0, 0x3003E70, 0x0, 0x3003E73, 0x0, 0x3003E76, 0x0, 0x3003E79, 0x0, 0x0, 0x0, 0x0, 0x3003E7C, 0x0, 0x0, 0x0, 0x0, 0x3003E7F, 0x0, 0x3003E82, 0x0, 0x0, 0x0, 0x3003E85, 0x0, 0x3003E88, 0x0, 0x3003E8B, 0x0, 0x3003E8E, 0x0, 0x3003E91, 0x0, 0x3003E94, 0x0, 0x3003E97, 0x0, 0x3003E9A, 0x0, 0x3003E9D, 0x0, 0x3003EA0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2004B02, 0x2004B04, 0x2004B06, 0x3004B08, 0x3004B0B, 0x2004B0E, 0x2004B0E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4004B10, 0x4004B14, 0x4004B18, 0x4004B1C, 0x4004B20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3003EC5, 0x3003EC8, 0x3003ECB, 0x3003ECE, 0x3003ED1, 0x3003ED4, 0x3003ED7, 0x3003EDA, 0x3003EDD, 0x3003EE0, 0x3003EE3, 0x3003EE6, 0x3003EE9, 0x3003EEC, 0x3003EEF, 0x3003EF2, 0x3003EF5, 0x3003EF8, 0x3003EFB, 0x3003EFE, 0x3003F01, 0x3003F04, 0x3003F07, 0x3003F0A, 0x3003F0D, 0x3003F10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4003F13, 0x4003F17, 0x4003F1B, 0x4003F1F, 0x4003F23, 0x4003F27, 0x4003F2B, 0x4003F2F, 0x4003F33, 0x4003F37, 0x4003F3B, 0x4003F3F, 0x4003F43, 0x4003F47, 0x4003F4B, 0x4003F4F, 0x4003F53, 0x4003F57, 0x4003F5B, 0x4003F5F, 0x4003F63, 0x4003F67, 0x4003F6B, 0x4003F6F, 0x4003F73, 0x4003F77, 0x4003F7B, 0x4003F7F, 0x4003F83, 0x4003F87, 0x4003F8B, 0x4003F8F, 0x4003F93, 0x4003F97, 0x4003F9B, 0x4003F9F, 0x4003FA3, 0x4003FA7, 0x4003FAB, 0x4003FAF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4003FB3, 0x4003FB7, 0x4003FBB, 0x4003FBF, 0x4003FC3, 0x4003FC7, 0x4003FCB, 0x4003FCF, 0x4003FD3, 0x4003FD7, 0x4003FDB, 0x4003FDF, 0x4003FE3, 0x4003FE7, 0x4003FEB, 0x4003FEF, 0x4003FF3, 0x4003FF7, 0x4003FFB, 0x4003FFF, 0x4004003, 0x4004007, 0x400400B, 0x400400F, 0x4004013, 0x4004017, 0x400401B, 0x400401F, 0x4004023, 0x4004027, 0x400402B, 0x400402F, }; const uint32_t* TitlecaseDataPtr = TitlecaseData; const uint32_t CaseFoldingIndex1[272] = { 0, 128, 256, 384, 360, 360, 360, 360, 360, 360, 512, 360, 360, 360, 360, 640, 768, 896, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, }; const uint32_t* CaseFoldingIndex1Ptr = CaseFoldingIndex1; const uint32_t CaseFoldingIndex2[1024] = { 0x0, 0x0, 0x20, 0x0, 0x0, 0x40, 0x60, 0x0, 0x80, 0xA0, 0xC0, 0xE0, 0x100, 0x120, 0x140, 0x160, 0x180, 0x1A0, 0x1C0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1E0, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x0, 0x2E0, 0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x0, 0x3E0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x400, 0x420, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x440, 0x460, 0x480, 0x4A0, 0x4C0, 0x4E0, 0x500, 0x520, 0x540, 0x560, 0x580, 0x5A0, 0x5C0, 0x5E0, 0x600, 0x620, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x640, 0x0, 0x660, 0x680, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6A0, 0x6C0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6E0, 0x700, 0x0, 0x720, 0x740, 0x760, 0x780, 0x7A0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7C0, 0x7E0, 0x800, 0x0, 0x0, 0x0, 0x0, 0x820, 0x840, 0x860, 0x880, 0x8A0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8C0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8E0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x900, 0x920, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x940, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, }; const uint32_t* CaseFoldingIndex2Ptr = CaseFoldingIndex2; const uint32_t CaseFoldingData[2400] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x100004E, 0x1000636, 0x1000060, 0x10000CC, 0x1000063, 0x100069A, 0x10000F0, 0x1000108, 0x100006F, 0x1000129, 0x100012F, 0x1000135, 0x1000702, 0x100007B, 0x100007E, 0x1000754, 0x1002068, 0x100016B, 0x100017D, 0x1000195, 0x100008D, 0x10007E4, 0x10001C5, 0x100080E, 0x1000099, 0x10001D4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2001D29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2004033, 0x2004035, 0x2004037, 0x2004039, 0x200403B, 0x200403D, 0x2000247, 0x200403F, 0x2004041, 0x2004043, 0x2004045, 0x2004047, 0x2004049, 0x200404B, 0x200404D, 0x200404F, 0x2001E1E, 0x2004051, 0x2004053, 0x2004055, 0x2004057, 0x2004059, 0x200405B, 0x0, 0x2000294, 0x200405D, 0x200405F, 0x2004061, 0x2004063, 0x2004065, 0x2004067, 0x2004B24, 0x2004069, 0x0, 0x200406B, 0x0, 0x200406D, 0x0, 0x200406F, 0x0, 0x2004071, 0x0, 0x2004073, 0x0, 0x2004075, 0x0, 0x2004077, 0x0, 0x2004079, 0x0, 0x200407B, 0x0, 0x200407D, 0x0, 0x200407F, 0x0, 0x2004081, 0x0, 0x2004083, 0x0, 0x2004085, 0x0, 0x2004087, 0x0, 0x2004089, 0x0, 0x200408B, 0x0, 0x200408D, 0x0, 0x2001EF8, 0x0, 0x200408F, 0x0, 0x2004091, 0x0, 0x2004093, 0x0, 0x2004095, 0x0, 0x3004097, 0x0, 0x200409A, 0x0, 0x200409C, 0x0, 0x200409E, 0x0, 0x0, 0x20040A0, 0x0, 0x20040A2, 0x0, 0x20040A4, 0x0, 0x20040A6, 0x0, 0x20040A8, 0x0, 0x20040AA, 0x0, 0x20040AC, 0x0, 0x20040AE, 0x0, 0x3001D48, 0x2001E00, 0x0, 0x20040B0, 0x0, 0x20040B2, 0x0, 0x20040B4, 0x0, 0x2002CE5, 0x0, 0x20040B6, 0x0, 0x20040B8, 0x0, 0x20040BA, 0x0, 0x20040BC, 0x0, 0x20040BE, 0x0, 0x20040C0, 0x0, 0x20040C2, 0x0, 0x20040C4, 0x0, 0x20040C6, 0x0, 0x20040C8, 0x0, 0x20040CA, 0x0, 0x20040CC, 0x0, 0x20040CE, 0x0, 0x20040D0, 0x0, 0x20040D2, 0x0, 0x20040D4, 0x0, 0x20040D6, 0x0, 0x20040D8, 0x0, 0x20040DA, 0x20040DC, 0x0, 0x20040DE, 0x0, 0x20040E0, 0x0, 0x100017D, 0x0, 0x20040E2, 0x20040E4, 0x0, 0x20040E6, 0x0, 0x2001E02, 0x20040E8, 0x0, 0x20040EA, 0x20040EC, 0x20040EE, 0x0, 0x0, 0x20040F0, 0x2001DFA, 0x2001DFC, 0x20040F2, 0x0, 0x20040F4, 0x2001D7D, 0x0, 0x2001E28, 0x2001E26, 0x20040F6, 0x0, 0x0, 0x0, 0x2001E0D, 0x2001E3C, 0x0, 0x2001E42, 0x20040F8, 0x0, 0x20040FA, 0x0, 0x20040FC, 0x0, 0x20040FE, 0x2004100, 0x0, 0x2001E48, 0x0, 0x0, 0x2004102, 0x0, 0x2004104, 0x2004106, 0x0, 0x2001E4E, 0x2001E53, 0x2004108, 0x0, 0x200410A, 0x0, 0x200026B, 0x200410C, 0x0, 0x0, 0x0, 0x200410E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2004110, 0x2004110, 0x0, 0x2004112, 0x2004112, 0x0, 0x2004114, 0x2004114, 0x0, 0x2004116, 0x0, 0x2004118, 0x0, 0x200411A, 0x0, 0x200411C, 0x0, 0x200411E, 0x0, 0x2004120, 0x0, 0x2004122, 0x0, 0x2004124, 0x0, 0x0, 0x2004126, 0x0, 0x2004128, 0x0, 0x200412A, 0x0, 0x200412C, 0x0, 0x200412E, 0x0, 0x2004130, 0x0, 0x2004132, 0x0, 0x2004134, 0x0, 0x2004136, 0x0, 0x300026F, 0x2004138, 0x2004138, 0x0, 0x200413A, 0x0, 0x200413C, 0x200413E, 0x2004140, 0x0, 0x2004142, 0x0, 0x2004144, 0x0, 0x2004146, 0x0, 0x2004148, 0x0, 0x200414A, 0x0, 0x200414C, 0x0, 0x200414E, 0x0, 0x2004150, 0x0, 0x2004152, 0x0, 0x2004154, 0x0, 0x2004156, 0x0, 0x2004158, 0x0, 0x200415A, 0x0, 0x200415C, 0x0, 0x200415E, 0x0, 0x2004160, 0x0, 0x2004162, 0x0, 0x2004164, 0x0, 0x2004166, 0x0, 0x2004168, 0x0, 0x200416A, 0x0, 0x200416C, 0x0, 0x200416E, 0x0, 0x2004170, 0x0, 0x2004172, 0x0, 0x2004174, 0x0, 0x2004176, 0x0, 0x2004178, 0x0, 0x200417A, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x300417C, 0x200417F, 0x0, 0x2004181, 0x3004183, 0x0, 0x0, 0x2004186, 0x0, 0x2004188, 0x2001E4C, 0x2001E55, 0x200418A, 0x0, 0x200418C, 0x0, 0x200418E, 0x0, 0x2004190, 0x0, 0x2004192, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000349, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2004194, 0x0, 0x2004196, 0x0, 0x0, 0x0, 0x2004198, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200419A, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200419C, 0x0, 0x200419E, 0x20041A0, 0x20041A2, 0x0, 0x20041A4, 0x0, 0x20041A6, 0x20041A8, 0x6000349, 0x2000357, 0x2001D89, 0x2001E12, 0x2001E14, 0x200035B, 0x2003369, 0x200035F, 0x2001D8B, 0x2000349, 0x2001D91, 0x200336B, 0x2001D29, 0x200336D, 0x200336F, 0x200036D, 0x2001D8F, 0x2000E17, 0x0, 0x2003371, 0x2003373, 0x2000367, 0x2001D8D, 0x2001E16, 0x2003375, 0x2000375, 0x20041AA, 0x20041AC, 0x0, 0x0, 0x0, 0x0, 0x6000367, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2003371, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20041AE, 0x2001D89, 0x2001D8B, 0x0, 0x0, 0x0, 0x2001D8D, 0x2001D8F, 0x0, 0x20041B0, 0x0, 0x20041B2, 0x0, 0x200337C, 0x0, 0x20041B4, 0x0, 0x20041B6, 0x0, 0x20041B8, 0x0, 0x20041BA, 0x0, 0x20041BC, 0x0, 0x20041BE, 0x0, 0x20041C0, 0x0, 0x20041C2, 0x0, 0x20041C4, 0x0, 0x2001D91, 0x2000E17, 0x0, 0x0, 0x2001D8B, 0x200035B, 0x0, 0x20041C6, 0x0, 0x20041C8, 0x20041CA, 0x0, 0x0, 0x20041CC, 0x20041CE, 0x20041D0, 0x20041D2, 0x20041D4, 0x20041D6, 0x20041D8, 0x20041DA, 0x20041DC, 0x20003B1, 0x20041DE, 0x20041E0, 0x20041E2, 0x20041E4, 0x20041E6, 0x20041E8, 0x20041EA, 0x20041EC, 0x20041EE, 0x20003D5, 0x20041F0, 0x20041F2, 0x20003AD, 0x20041F4, 0x20003A5, 0x20003CD, 0x20003FD, 0x20003A1, 0x20041F6, 0x20003B5, 0x20041F8, 0x20041FA, 0x2001E18, 0x2000415, 0x20041FC, 0x20041FE, 0x2004200, 0x2004202, 0x20003BD, 0x2004204, 0x2004206, 0x2004208, 0x2000445, 0x200420A, 0x200420C, 0x2002CDC, 0x200044D, 0x2002CDE, 0x2000425, 0x200420E, 0x2004210, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2004212, 0x0, 0x2004214, 0x0, 0x2004216, 0x0, 0x2004218, 0x0, 0x200421A, 0x0, 0x200421C, 0x0, 0x200421E, 0x0, 0x2004220, 0x0, 0x2004222, 0x0, 0x2004224, 0x0, 0x20003C5, 0x0, 0x2004226, 0x0, 0x2004228, 0x0, 0x200422A, 0x0, 0x200422C, 0x0, 0x200422E, 0x0, 0x2004230, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2004232, 0x0, 0x2004234, 0x0, 0x2004236, 0x0, 0x2004238, 0x0, 0x200423A, 0x0, 0x200423C, 0x0, 0x200423E, 0x0, 0x2004240, 0x0, 0x2004242, 0x0, 0x2004244, 0x0, 0x2004246, 0x0, 0x2004248, 0x0, 0x200424A, 0x0, 0x200424C, 0x0, 0x200424E, 0x0, 0x2004250, 0x0, 0x2004252, 0x0, 0x2004254, 0x0, 0x2004256, 0x0, 0x2004258, 0x0, 0x200425A, 0x0, 0x200425C, 0x0, 0x200425E, 0x0, 0x2004260, 0x0, 0x2004262, 0x0, 0x2004264, 0x0, 0x2004266, 0x0, 0x2004268, 0x200426A, 0x0, 0x200426C, 0x0, 0x200426E, 0x0, 0x2004270, 0x0, 0x2004272, 0x0, 0x2004274, 0x0, 0x2004276, 0x0, 0x0, 0x2004278, 0x0, 0x200427A, 0x0, 0x200427C, 0x0, 0x200427E, 0x0, 0x20003ED, 0x0, 0x2004280, 0x0, 0x2004282, 0x0, 0x2004284, 0x0, 0x2004286, 0x0, 0x2004288, 0x0, 0x200428A, 0x0, 0x200428C, 0x0, 0x200041D, 0x0, 0x200428E, 0x0, 0x2004290, 0x0, 0x2004292, 0x0, 0x2004294, 0x0, 0x2004296, 0x0, 0x2004298, 0x0, 0x200429A, 0x0, 0x200429C, 0x0, 0x200429E, 0x0, 0x20042A0, 0x0, 0x20042A2, 0x0, 0x20042A4, 0x0, 0x20042A6, 0x0, 0x20042A8, 0x0, 0x20042AA, 0x0, 0x20042AC, 0x0, 0x20042AE, 0x0, 0x20042B0, 0x0, 0x20042B2, 0x0, 0x20042B4, 0x0, 0x20042B6, 0x0, 0x20042B8, 0x0, 0x20042BA, 0x0, 0x20042BC, 0x0, 0x20042BE, 0x0, 0x20042C0, 0x0, 0x20042C2, 0x0, 0x20042C4, 0x0, 0x20042C6, 0x0, 0x20042C8, 0x0, 0x20042CA, 0x0, 0x20042CC, 0x0, 0x20042CE, 0x0, 0x20042D0, 0x0, 0x20042D2, 0x0, 0x0, 0x20042D4, 0x20042D6, 0x20042D8, 0x20042DA, 0x2001D99, 0x20042DC, 0x20042DE, 0x20042E0, 0x20042E2, 0x20042E4, 0x2002D0A, 0x20042E6, 0x2002D12, 0x20042E8, 0x20042EA, 0x20042EC, 0x20042EE, 0x20042F0, 0x20042F2, 0x2002D00, 0x20042F4, 0x2002D02, 0x20042F6, 0x20042F8, 0x20042FA, 0x20042FC, 0x20042FE, 0x2004300, 0x2004302, 0x2002D0C, 0x2004304, 0x2004306, 0x2004308, 0x2001D9B, 0x200430A, 0x200430C, 0x200430E, 0x2004310, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4001D99, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004312, 0x3004315, 0x3004318, 0x300431B, 0x300431E, 0x3004321, 0x3004324, 0x3004327, 0x300432A, 0x300432D, 0x3004330, 0x3004333, 0x3004336, 0x3004339, 0x300433C, 0x300433F, 0x3004342, 0x3004345, 0x3004348, 0x300434B, 0x300434E, 0x3004351, 0x3004354, 0x3004357, 0x300435A, 0x300435D, 0x3004360, 0x3004363, 0x3004366, 0x3004369, 0x300436C, 0x300436F, 0x3004372, 0x3004375, 0x3004378, 0x300437B, 0x300437E, 0x3004381, 0x0, 0x3004384, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004387, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x300438A, 0x0, 0x300438D, 0x0, 0x3004390, 0x0, 0x3004393, 0x0, 0x3004396, 0x0, 0x3004399, 0x0, 0x300439C, 0x0, 0x300439F, 0x0, 0x30043A2, 0x0, 0x30043A5, 0x0, 0x30043A8, 0x0, 0x30043AB, 0x0, 0x30043AE, 0x0, 0x30043B1, 0x0, 0x30043B4, 0x0, 0x30043B7, 0x0, 0x30043BA, 0x0, 0x30043BD, 0x0, 0x30043C0, 0x0, 0x30043C3, 0x0, 0x30043C6, 0x0, 0x30043C9, 0x0, 0x30043CC, 0x0, 0x30043CF, 0x0, 0x30043D2, 0x0, 0x30043D5, 0x0, 0x30043D8, 0x0, 0x30043DB, 0x0, 0x30043DE, 0x0, 0x30043E1, 0x0, 0x30043E4, 0x0, 0x30043E7, 0x0, 0x30043EA, 0x0, 0x30043ED, 0x0, 0x30043F0, 0x0, 0x30043F3, 0x0, 0x30043F6, 0x0, 0x30043F9, 0x0, 0x30043FC, 0x0, 0x30043FF, 0x0, 0x3004402, 0x0, 0x3004405, 0x0, 0x3004408, 0x0, 0x300440B, 0x0, 0x300440E, 0x0, 0x3004411, 0x0, 0x3004414, 0x0, 0x3004417, 0x0, 0x300441A, 0x0, 0x300441D, 0x0, 0x3004420, 0x0, 0x3004423, 0x0, 0x3004426, 0x0, 0x3004429, 0x0, 0x300442C, 0x0, 0x300442F, 0x0, 0x3004432, 0x0, 0x3004435, 0x0, 0x3004438, 0x0, 0x300443B, 0x0, 0x300443E, 0x0, 0x3004441, 0x0, 0x3004444, 0x0, 0x3004447, 0x0, 0x300444A, 0x0, 0x300444D, 0x0, 0x3004450, 0x0, 0x3004453, 0x0, 0x3004456, 0x0, 0x3004459, 0x0, 0x300445C, 0x0, 0x300445F, 0x0, 0x3004462, 0x0, 0x3004465, 0x0, 0x3004468, 0x0, 0x300082F, 0x3000832, 0x3000835, 0x3000838, 0x3001E5B, 0x300441A, 0x0, 0x0, 0x2004B24, 0x0, 0x300446D, 0x0, 0x3004470, 0x0, 0x3004473, 0x0, 0x3004476, 0x0, 0x3004479, 0x0, 0x300447C, 0x0, 0x300447F, 0x0, 0x3004482, 0x0, 0x3004485, 0x0, 0x3004488, 0x0, 0x300448B, 0x0, 0x300448E, 0x0, 0x3004491, 0x0, 0x3004494, 0x0, 0x3004497, 0x0, 0x300449A, 0x0, 0x300449D, 0x0, 0x30044A0, 0x0, 0x30044A3, 0x0, 0x30044A6, 0x0, 0x30044A9, 0x0, 0x30044AC, 0x0, 0x30044AF, 0x0, 0x30044B2, 0x0, 0x30044B5, 0x0, 0x30044B8, 0x0, 0x30044BB, 0x0, 0x30044BE, 0x0, 0x30044C1, 0x0, 0x30044C4, 0x0, 0x30044C7, 0x0, 0x30044CA, 0x0, 0x30044CD, 0x0, 0x30044D0, 0x0, 0x30044D3, 0x0, 0x30044D6, 0x0, 0x30044D9, 0x0, 0x30044DC, 0x0, 0x30044DF, 0x0, 0x30044E2, 0x0, 0x30044E5, 0x0, 0x30044E8, 0x0, 0x30044EB, 0x0, 0x30044EE, 0x0, 0x30044F1, 0x0, 0x30044F4, 0x0, 0x30044F7, 0x0, 0x30044FA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30044FD, 0x3004500, 0x3004503, 0x3004506, 0x3004509, 0x300450C, 0x300450F, 0x3004512, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004515, 0x3004518, 0x300451B, 0x300451E, 0x3004521, 0x3004524, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004527, 0x300452A, 0x300452D, 0x3004530, 0x3004533, 0x3004536, 0x3004539, 0x300453C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x300453F, 0x3004542, 0x3004545, 0x3004548, 0x300454B, 0x300454E, 0x3004551, 0x3004554, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004557, 0x300455A, 0x300455D, 0x3004560, 0x3004563, 0x3004566, 0x0, 0x0, 0x4000B4D, 0x0, 0x6000B55, 0x0, 0x6000B61, 0x0, 0x6000B6D, 0x0, 0x0, 0x3004569, 0x0, 0x300456C, 0x0, 0x300456F, 0x0, 0x3004572, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004575, 0x3004578, 0x300457B, 0x300457E, 0x3004581, 0x3004584, 0x3004587, 0x300458A, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5004B26, 0x5004B2B, 0x5004B30, 0x5004B35, 0x5004B3A, 0x5004B3F, 0x5004B44, 0x5004B49, 0x5004B26, 0x5004B2B, 0x5004B30, 0x5004B35, 0x5004B3A, 0x5004B3F, 0x5004B44, 0x5004B49, 0x5004B4E, 0x5004B53, 0x5004B58, 0x5004B5D, 0x5004B62, 0x5004B67, 0x5004B6C, 0x5004B71, 0x5004B4E, 0x5004B53, 0x5004B58, 0x5004B5D, 0x5004B62, 0x5004B67, 0x5004B6C, 0x5004B71, 0x5004B76, 0x5004B7B, 0x5004B80, 0x5004B85, 0x5004B8A, 0x5004B8F, 0x5004B94, 0x5004B99, 0x5004B76, 0x5004B7B, 0x5004B80, 0x5004B85, 0x5004B8A, 0x5004B8F, 0x5004B94, 0x5004B99, 0x0, 0x0, 0x5004B9E, 0x4004BA3, 0x4004BA7, 0x0, 0x4000D83, 0x6004BAB, 0x30045D5, 0x30045D8, 0x30045DB, 0x30045DE, 0x4004BA3, 0x0, 0x2000349, 0x0, 0x0, 0x0, 0x5004BB1, 0x4004BB6, 0x4004BBA, 0x0, 0x4000DB1, 0x6004BBE, 0x30045E4, 0x30045E7, 0x30045EA, 0x30045ED, 0x4004BB6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000DDE, 0x6000349, 0x0, 0x0, 0x4000DE4, 0x6000DE8, 0x30045F3, 0x30045F6, 0x30045F9, 0x30045FC, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000E11, 0x6000367, 0x4000E17, 0x0, 0x4000E1F, 0x6000E23, 0x30045FF, 0x3004602, 0x3004605, 0x3004608, 0x300460B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5004BC4, 0x4004BC9, 0x4004BCD, 0x0, 0x4000E4E, 0x6004BD1, 0x300460E, 0x3004611, 0x3004614, 0x3004617, 0x4004BC9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000375, 0x0, 0x0, 0x0, 0x100012F, 0x200403D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x300461D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004620, 0x3004623, 0x3004626, 0x3004629, 0x300462C, 0x300462F, 0x3004632, 0x3004635, 0x3004638, 0x300463B, 0x300463E, 0x3004641, 0x3004644, 0x3004647, 0x300464A, 0x300464D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004650, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004653, 0x3004656, 0x3004659, 0x300465C, 0x300465F, 0x3004662, 0x3004665, 0x3004668, 0x300466B, 0x300466E, 0x3004671, 0x3004674, 0x3004677, 0x300467A, 0x300467D, 0x3004680, 0x3004683, 0x3004686, 0x3004689, 0x300468C, 0x300468F, 0x3004692, 0x3004695, 0x3004698, 0x300469B, 0x300469E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30046A1, 0x30046A4, 0x30046A7, 0x30046AA, 0x30046AD, 0x30046B0, 0x30046B3, 0x30046B6, 0x30046B9, 0x30046BC, 0x30046BF, 0x30046C2, 0x30046C5, 0x30046C8, 0x30046CB, 0x30046CE, 0x30046D1, 0x30046D4, 0x30046D7, 0x30046DA, 0x30046DD, 0x30046E0, 0x30046E3, 0x30046E6, 0x30046E9, 0x30046EC, 0x30046EF, 0x30046F2, 0x30046F5, 0x30046F8, 0x30046FB, 0x30046FE, 0x3004701, 0x3004704, 0x3004707, 0x300470A, 0x300470D, 0x3004710, 0x3004713, 0x3004716, 0x3004719, 0x300471C, 0x300471F, 0x3004722, 0x3004725, 0x3004728, 0x300472B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x300472E, 0x0, 0x2002CED, 0x3004731, 0x2004734, 0x0, 0x0, 0x3004736, 0x0, 0x3004739, 0x0, 0x300473C, 0x0, 0x2001DF5, 0x2001E38, 0x2001DF3, 0x2001E1A, 0x0, 0x300473F, 0x0, 0x0, 0x3004742, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2004745, 0x2004747, 0x3004749, 0x0, 0x300474C, 0x0, 0x300474F, 0x0, 0x3004752, 0x0, 0x3004755, 0x0, 0x3004758, 0x0, 0x300475B, 0x0, 0x300475E, 0x0, 0x3004761, 0x0, 0x3004764, 0x0, 0x3004767, 0x0, 0x300476A, 0x0, 0x300476D, 0x0, 0x3004770, 0x0, 0x3004773, 0x0, 0x3004776, 0x0, 0x3004779, 0x0, 0x300477C, 0x0, 0x300477F, 0x0, 0x3004782, 0x0, 0x3004785, 0x0, 0x3004788, 0x0, 0x300478B, 0x0, 0x300478E, 0x0, 0x3004791, 0x0, 0x3004794, 0x0, 0x3004797, 0x0, 0x300479A, 0x0, 0x300479D, 0x0, 0x30047A0, 0x0, 0x30047A3, 0x0, 0x30047A6, 0x0, 0x30047A9, 0x0, 0x30047AC, 0x0, 0x30047AF, 0x0, 0x30047B2, 0x0, 0x30047B5, 0x0, 0x30047B8, 0x0, 0x30047BB, 0x0, 0x30047BE, 0x0, 0x30047C1, 0x0, 0x30047C4, 0x0, 0x30047C7, 0x0, 0x30047CA, 0x0, 0x30047CD, 0x0, 0x30047D0, 0x0, 0x30047D3, 0x0, 0x30047D6, 0x0, 0x30047D9, 0x0, 0x30047DC, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30047DF, 0x0, 0x30047E2, 0x0, 0x0, 0x0, 0x0, 0x30047E5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30047E8, 0x0, 0x30047EB, 0x0, 0x30047EE, 0x0, 0x30047F1, 0x0, 0x30047F4, 0x0, 0x30047F7, 0x0, 0x30047FA, 0x0, 0x30047FD, 0x0, 0x3004800, 0x0, 0x3004803, 0x0, 0x3004806, 0x0, 0x3004809, 0x0, 0x300480C, 0x0, 0x300480F, 0x0, 0x3004812, 0x0, 0x3004815, 0x0, 0x3004818, 0x0, 0x300481B, 0x0, 0x300481E, 0x0, 0x3004821, 0x0, 0x3004824, 0x0, 0x3004827, 0x0, 0x300482A, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x300482D, 0x0, 0x3004830, 0x0, 0x3004833, 0x0, 0x3004836, 0x0, 0x3004839, 0x0, 0x300483C, 0x0, 0x300483F, 0x0, 0x3004842, 0x0, 0x3004845, 0x0, 0x3004848, 0x0, 0x300484B, 0x0, 0x300484E, 0x0, 0x3004851, 0x0, 0x3004854, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004857, 0x0, 0x300485A, 0x0, 0x3002CE7, 0x0, 0x300485D, 0x0, 0x3004860, 0x0, 0x3004863, 0x0, 0x3004866, 0x0, 0x0, 0x0, 0x3004869, 0x0, 0x300486C, 0x0, 0x300486F, 0x0, 0x3004872, 0x0, 0x3004875, 0x0, 0x3004878, 0x0, 0x300487B, 0x0, 0x300487E, 0x0, 0x3004881, 0x0, 0x3004884, 0x0, 0x3004887, 0x0, 0x300488A, 0x0, 0x300488D, 0x0, 0x3004890, 0x0, 0x3004893, 0x0, 0x3004896, 0x0, 0x3004899, 0x0, 0x300489C, 0x0, 0x300489F, 0x0, 0x30048A2, 0x0, 0x30048A5, 0x0, 0x30048A8, 0x0, 0x30048AB, 0x0, 0x30048AE, 0x0, 0x30048B1, 0x0, 0x30048B4, 0x0, 0x30048B7, 0x0, 0x30048BA, 0x0, 0x30048BD, 0x0, 0x30048C0, 0x0, 0x3002CE0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30048C3, 0x0, 0x30048C6, 0x0, 0x30048C9, 0x30048CC, 0x0, 0x30048CF, 0x0, 0x30048D2, 0x0, 0x30048D5, 0x0, 0x30048D8, 0x0, 0x0, 0x0, 0x0, 0x30048DB, 0x0, 0x2001E24, 0x0, 0x0, 0x30048DE, 0x0, 0x30048E1, 0x0, 0x0, 0x0, 0x30048E4, 0x0, 0x30048E7, 0x0, 0x30048EA, 0x0, 0x30048ED, 0x0, 0x30048F0, 0x0, 0x30048F3, 0x0, 0x30048F6, 0x0, 0x30048F9, 0x0, 0x30048FC, 0x0, 0x30048FF, 0x0, 0x2001D63, 0x2001DFE, 0x2001E22, 0x2004902, 0x0, 0x0, 0x2004904, 0x2004906, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2002CF2, 0x2002CF4, 0x2002CF6, 0x3002CF8, 0x3002CFB, 0x2002CFE, 0x2002CFE, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4002D00, 0x4002D04, 0x4002D08, 0x4002D0C, 0x4002D10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3004908, 0x300490B, 0x300490E, 0x3004911, 0x3004914, 0x3004917, 0x300491A, 0x300491D, 0x3004920, 0x3004923, 0x3004926, 0x3004929, 0x300492C, 0x300492F, 0x3004932, 0x3004935, 0x3004938, 0x300493B, 0x300493E, 0x3004941, 0x3004944, 0x3004947, 0x300494A, 0x300494D, 0x3004950, 0x3004953, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4004956, 0x400495A, 0x400495E, 0x4004962, 0x4004966, 0x400496A, 0x400496E, 0x4004972, 0x4004976, 0x400497A, 0x400497E, 0x4004982, 0x4004986, 0x400498A, 0x400498E, 0x4004992, 0x4004996, 0x400499A, 0x400499E, 0x40049A2, 0x40049A6, 0x40049AA, 0x40049AE, 0x40049B2, 0x40049B6, 0x40049BA, 0x40049BE, 0x40049C2, 0x40049C6, 0x40049CA, 0x40049CE, 0x40049D2, 0x40049D6, 0x40049DA, 0x40049DE, 0x40049E2, 0x40049E6, 0x40049EA, 0x40049EE, 0x40049F2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40049F6, 0x40049FA, 0x40049FE, 0x4004A02, 0x4004A06, 0x4004A0A, 0x4004A0E, 0x4004A12, 0x4004A16, 0x4004A1A, 0x4004A1E, 0x4004A22, 0x4004A26, 0x4004A2A, 0x4004A2E, 0x4004A32, 0x4004A36, 0x4004A3A, 0x4004A3E, 0x4004A42, 0x4004A46, 0x4004A4A, 0x4004A4E, 0x4004A52, 0x4004A56, 0x4004A5A, 0x4004A5E, 0x4004A62, 0x4004A66, 0x4004A6A, 0x4004A6E, 0x4004A72, }; const uint32_t* CaseFoldingDataPtr = CaseFoldingData; const size_t UnicodeCompositionRecordCount = 940; const CompositionRecord UnicodeCompositionRecord[940] = { { 0x3c00000338, 0x226e }, { 0x3d00000338, 0x2260 }, { 0x3e00000338, 0x226f }, { 0x4100000300, 0xc0 }, { 0x4100000301, 0xc1 }, { 0x4100000302, 0xc2 }, { 0x4100000303, 0xc3 }, { 0x4100000304, 0x100 }, { 0x4100000306, 0x102 }, { 0x4100000307, 0x226 }, { 0x4100000308, 0xc4 }, { 0x4100000309, 0x1ea2 }, { 0x410000030a, 0xc5 }, { 0x410000030c, 0x1cd }, { 0x410000030f, 0x200 }, { 0x4100000311, 0x202 }, { 0x4100000323, 0x1ea0 }, { 0x4100000325, 0x1e00 }, { 0x4100000328, 0x104 }, { 0x4200000307, 0x1e02 }, { 0x4200000323, 0x1e04 }, { 0x4200000331, 0x1e06 }, { 0x4300000301, 0x106 }, { 0x4300000302, 0x108 }, { 0x4300000307, 0x10a }, { 0x430000030c, 0x10c }, { 0x4300000327, 0xc7 }, { 0x4400000307, 0x1e0a }, { 0x440000030c, 0x10e }, { 0x4400000323, 0x1e0c }, { 0x4400000327, 0x1e10 }, { 0x440000032d, 0x1e12 }, { 0x4400000331, 0x1e0e }, { 0x4500000300, 0xc8 }, { 0x4500000301, 0xc9 }, { 0x4500000302, 0xca }, { 0x4500000303, 0x1ebc }, { 0x4500000304, 0x112 }, { 0x4500000306, 0x114 }, { 0x4500000307, 0x116 }, { 0x4500000308, 0xcb }, { 0x4500000309, 0x1eba }, { 0x450000030c, 0x11a }, { 0x450000030f, 0x204 }, { 0x4500000311, 0x206 }, { 0x4500000323, 0x1eb8 }, { 0x4500000327, 0x228 }, { 0x4500000328, 0x118 }, { 0x450000032d, 0x1e18 }, { 0x4500000330, 0x1e1a }, { 0x4600000307, 0x1e1e }, { 0x4700000301, 0x1f4 }, { 0x4700000302, 0x11c }, { 0x4700000304, 0x1e20 }, { 0x4700000306, 0x11e }, { 0x4700000307, 0x120 }, { 0x470000030c, 0x1e6 }, { 0x4700000327, 0x122 }, { 0x4800000302, 0x124 }, { 0x4800000307, 0x1e22 }, { 0x4800000308, 0x1e26 }, { 0x480000030c, 0x21e }, { 0x4800000323, 0x1e24 }, { 0x4800000327, 0x1e28 }, { 0x480000032e, 0x1e2a }, { 0x4900000300, 0xcc }, { 0x4900000301, 0xcd }, { 0x4900000302, 0xce }, { 0x4900000303, 0x128 }, { 0x4900000304, 0x12a }, { 0x4900000306, 0x12c }, { 0x4900000307, 0x130 }, { 0x4900000308, 0xcf }, { 0x4900000309, 0x1ec8 }, { 0x490000030c, 0x1cf }, { 0x490000030f, 0x208 }, { 0x4900000311, 0x20a }, { 0x4900000323, 0x1eca }, { 0x4900000328, 0x12e }, { 0x4900000330, 0x1e2c }, { 0x4a00000302, 0x134 }, { 0x4b00000301, 0x1e30 }, { 0x4b0000030c, 0x1e8 }, { 0x4b00000323, 0x1e32 }, { 0x4b00000327, 0x136 }, { 0x4b00000331, 0x1e34 }, { 0x4c00000301, 0x139 }, { 0x4c0000030c, 0x13d }, { 0x4c00000323, 0x1e36 }, { 0x4c00000327, 0x13b }, { 0x4c0000032d, 0x1e3c }, { 0x4c00000331, 0x1e3a }, { 0x4d00000301, 0x1e3e }, { 0x4d00000307, 0x1e40 }, { 0x4d00000323, 0x1e42 }, { 0x4e00000300, 0x1f8 }, { 0x4e00000301, 0x143 }, { 0x4e00000303, 0xd1 }, { 0x4e00000307, 0x1e44 }, { 0x4e0000030c, 0x147 }, { 0x4e00000323, 0x1e46 }, { 0x4e00000327, 0x145 }, { 0x4e0000032d, 0x1e4a }, { 0x4e00000331, 0x1e48 }, { 0x4f00000300, 0xd2 }, { 0x4f00000301, 0xd3 }, { 0x4f00000302, 0xd4 }, { 0x4f00000303, 0xd5 }, { 0x4f00000304, 0x14c }, { 0x4f00000306, 0x14e }, { 0x4f00000307, 0x22e }, { 0x4f00000308, 0xd6 }, { 0x4f00000309, 0x1ece }, { 0x4f0000030b, 0x150 }, { 0x4f0000030c, 0x1d1 }, { 0x4f0000030f, 0x20c }, { 0x4f00000311, 0x20e }, { 0x4f0000031b, 0x1a0 }, { 0x4f00000323, 0x1ecc }, { 0x4f00000328, 0x1ea }, { 0x5000000301, 0x1e54 }, { 0x5000000307, 0x1e56 }, { 0x5200000301, 0x154 }, { 0x5200000307, 0x1e58 }, { 0x520000030c, 0x158 }, { 0x520000030f, 0x210 }, { 0x5200000311, 0x212 }, { 0x5200000323, 0x1e5a }, { 0x5200000327, 0x156 }, { 0x5200000331, 0x1e5e }, { 0x5300000301, 0x15a }, { 0x5300000302, 0x15c }, { 0x5300000307, 0x1e60 }, { 0x530000030c, 0x160 }, { 0x5300000323, 0x1e62 }, { 0x5300000326, 0x218 }, { 0x5300000327, 0x15e }, { 0x5400000307, 0x1e6a }, { 0x540000030c, 0x164 }, { 0x5400000323, 0x1e6c }, { 0x5400000326, 0x21a }, { 0x5400000327, 0x162 }, { 0x540000032d, 0x1e70 }, { 0x5400000331, 0x1e6e }, { 0x5500000300, 0xd9 }, { 0x5500000301, 0xda }, { 0x5500000302, 0xdb }, { 0x5500000303, 0x168 }, { 0x5500000304, 0x16a }, { 0x5500000306, 0x16c }, { 0x5500000308, 0xdc }, { 0x5500000309, 0x1ee6 }, { 0x550000030a, 0x16e }, { 0x550000030b, 0x170 }, { 0x550000030c, 0x1d3 }, { 0x550000030f, 0x214 }, { 0x5500000311, 0x216 }, { 0x550000031b, 0x1af }, { 0x5500000323, 0x1ee4 }, { 0x5500000324, 0x1e72 }, { 0x5500000328, 0x172 }, { 0x550000032d, 0x1e76 }, { 0x5500000330, 0x1e74 }, { 0x5600000303, 0x1e7c }, { 0x5600000323, 0x1e7e }, { 0x5700000300, 0x1e80 }, { 0x5700000301, 0x1e82 }, { 0x5700000302, 0x174 }, { 0x5700000307, 0x1e86 }, { 0x5700000308, 0x1e84 }, { 0x5700000323, 0x1e88 }, { 0x5800000307, 0x1e8a }, { 0x5800000308, 0x1e8c }, { 0x5900000300, 0x1ef2 }, { 0x5900000301, 0xdd }, { 0x5900000302, 0x176 }, { 0x5900000303, 0x1ef8 }, { 0x5900000304, 0x232 }, { 0x5900000307, 0x1e8e }, { 0x5900000308, 0x178 }, { 0x5900000309, 0x1ef6 }, { 0x5900000323, 0x1ef4 }, { 0x5a00000301, 0x179 }, { 0x5a00000302, 0x1e90 }, { 0x5a00000307, 0x17b }, { 0x5a0000030c, 0x17d }, { 0x5a00000323, 0x1e92 }, { 0x5a00000331, 0x1e94 }, { 0x6100000300, 0xe0 }, { 0x6100000301, 0xe1 }, { 0x6100000302, 0xe2 }, { 0x6100000303, 0xe3 }, { 0x6100000304, 0x101 }, { 0x6100000306, 0x103 }, { 0x6100000307, 0x227 }, { 0x6100000308, 0xe4 }, { 0x6100000309, 0x1ea3 }, { 0x610000030a, 0xe5 }, { 0x610000030c, 0x1ce }, { 0x610000030f, 0x201 }, { 0x6100000311, 0x203 }, { 0x6100000323, 0x1ea1 }, { 0x6100000325, 0x1e01 }, { 0x6100000328, 0x105 }, { 0x6200000307, 0x1e03 }, { 0x6200000323, 0x1e05 }, { 0x6200000331, 0x1e07 }, { 0x6300000301, 0x107 }, { 0x6300000302, 0x109 }, { 0x6300000307, 0x10b }, { 0x630000030c, 0x10d }, { 0x6300000327, 0xe7 }, { 0x6400000307, 0x1e0b }, { 0x640000030c, 0x10f }, { 0x6400000323, 0x1e0d }, { 0x6400000327, 0x1e11 }, { 0x640000032d, 0x1e13 }, { 0x6400000331, 0x1e0f }, { 0x6500000300, 0xe8 }, { 0x6500000301, 0xe9 }, { 0x6500000302, 0xea }, { 0x6500000303, 0x1ebd }, { 0x6500000304, 0x113 }, { 0x6500000306, 0x115 }, { 0x6500000307, 0x117 }, { 0x6500000308, 0xeb }, { 0x6500000309, 0x1ebb }, { 0x650000030c, 0x11b }, { 0x650000030f, 0x205 }, { 0x6500000311, 0x207 }, { 0x6500000323, 0x1eb9 }, { 0x6500000327, 0x229 }, { 0x6500000328, 0x119 }, { 0x650000032d, 0x1e19 }, { 0x6500000330, 0x1e1b }, { 0x6600000307, 0x1e1f }, { 0x6700000301, 0x1f5 }, { 0x6700000302, 0x11d }, { 0x6700000304, 0x1e21 }, { 0x6700000306, 0x11f }, { 0x6700000307, 0x121 }, { 0x670000030c, 0x1e7 }, { 0x6700000327, 0x123 }, { 0x6800000302, 0x125 }, { 0x6800000307, 0x1e23 }, { 0x6800000308, 0x1e27 }, { 0x680000030c, 0x21f }, { 0x6800000323, 0x1e25 }, { 0x6800000327, 0x1e29 }, { 0x680000032e, 0x1e2b }, { 0x6800000331, 0x1e96 }, { 0x6900000300, 0xec }, { 0x6900000301, 0xed }, { 0x6900000302, 0xee }, { 0x6900000303, 0x129 }, { 0x6900000304, 0x12b }, { 0x6900000306, 0x12d }, { 0x6900000308, 0xef }, { 0x6900000309, 0x1ec9 }, { 0x690000030c, 0x1d0 }, { 0x690000030f, 0x209 }, { 0x6900000311, 0x20b }, { 0x6900000323, 0x1ecb }, { 0x6900000328, 0x12f }, { 0x6900000330, 0x1e2d }, { 0x6a00000302, 0x135 }, { 0x6a0000030c, 0x1f0 }, { 0x6b00000301, 0x1e31 }, { 0x6b0000030c, 0x1e9 }, { 0x6b00000323, 0x1e33 }, { 0x6b00000327, 0x137 }, { 0x6b00000331, 0x1e35 }, { 0x6c00000301, 0x13a }, { 0x6c0000030c, 0x13e }, { 0x6c00000323, 0x1e37 }, { 0x6c00000327, 0x13c }, { 0x6c0000032d, 0x1e3d }, { 0x6c00000331, 0x1e3b }, { 0x6d00000301, 0x1e3f }, { 0x6d00000307, 0x1e41 }, { 0x6d00000323, 0x1e43 }, { 0x6e00000300, 0x1f9 }, { 0x6e00000301, 0x144 }, { 0x6e00000303, 0xf1 }, { 0x6e00000307, 0x1e45 }, { 0x6e0000030c, 0x148 }, { 0x6e00000323, 0x1e47 }, { 0x6e00000327, 0x146 }, { 0x6e0000032d, 0x1e4b }, { 0x6e00000331, 0x1e49 }, { 0x6f00000300, 0xf2 }, { 0x6f00000301, 0xf3 }, { 0x6f00000302, 0xf4 }, { 0x6f00000303, 0xf5 }, { 0x6f00000304, 0x14d }, { 0x6f00000306, 0x14f }, { 0x6f00000307, 0x22f }, { 0x6f00000308, 0xf6 }, { 0x6f00000309, 0x1ecf }, { 0x6f0000030b, 0x151 }, { 0x6f0000030c, 0x1d2 }, { 0x6f0000030f, 0x20d }, { 0x6f00000311, 0x20f }, { 0x6f0000031b, 0x1a1 }, { 0x6f00000323, 0x1ecd }, { 0x6f00000328, 0x1eb }, { 0x7000000301, 0x1e55 }, { 0x7000000307, 0x1e57 }, { 0x7200000301, 0x155 }, { 0x7200000307, 0x1e59 }, { 0x720000030c, 0x159 }, { 0x720000030f, 0x211 }, { 0x7200000311, 0x213 }, { 0x7200000323, 0x1e5b }, { 0x7200000327, 0x157 }, { 0x7200000331, 0x1e5f }, { 0x7300000301, 0x15b }, { 0x7300000302, 0x15d }, { 0x7300000307, 0x1e61 }, { 0x730000030c, 0x161 }, { 0x7300000323, 0x1e63 }, { 0x7300000326, 0x219 }, { 0x7300000327, 0x15f }, { 0x7400000307, 0x1e6b }, { 0x7400000308, 0x1e97 }, { 0x740000030c, 0x165 }, { 0x7400000323, 0x1e6d }, { 0x7400000326, 0x21b }, { 0x7400000327, 0x163 }, { 0x740000032d, 0x1e71 }, { 0x7400000331, 0x1e6f }, { 0x7500000300, 0xf9 }, { 0x7500000301, 0xfa }, { 0x7500000302, 0xfb }, { 0x7500000303, 0x169 }, { 0x7500000304, 0x16b }, { 0x7500000306, 0x16d }, { 0x7500000308, 0xfc }, { 0x7500000309, 0x1ee7 }, { 0x750000030a, 0x16f }, { 0x750000030b, 0x171 }, { 0x750000030c, 0x1d4 }, { 0x750000030f, 0x215 }, { 0x7500000311, 0x217 }, { 0x750000031b, 0x1b0 }, { 0x7500000323, 0x1ee5 }, { 0x7500000324, 0x1e73 }, { 0x7500000328, 0x173 }, { 0x750000032d, 0x1e77 }, { 0x7500000330, 0x1e75 }, { 0x7600000303, 0x1e7d }, { 0x7600000323, 0x1e7f }, { 0x7700000300, 0x1e81 }, { 0x7700000301, 0x1e83 }, { 0x7700000302, 0x175 }, { 0x7700000307, 0x1e87 }, { 0x7700000308, 0x1e85 }, { 0x770000030a, 0x1e98 }, { 0x7700000323, 0x1e89 }, { 0x7800000307, 0x1e8b }, { 0x7800000308, 0x1e8d }, { 0x7900000300, 0x1ef3 }, { 0x7900000301, 0xfd }, { 0x7900000302, 0x177 }, { 0x7900000303, 0x1ef9 }, { 0x7900000304, 0x233 }, { 0x7900000307, 0x1e8f }, { 0x7900000308, 0xff }, { 0x7900000309, 0x1ef7 }, { 0x790000030a, 0x1e99 }, { 0x7900000323, 0x1ef5 }, { 0x7a00000301, 0x17a }, { 0x7a00000302, 0x1e91 }, { 0x7a00000307, 0x17c }, { 0x7a0000030c, 0x17e }, { 0x7a00000323, 0x1e93 }, { 0x7a00000331, 0x1e95 }, { 0xa800000300, 0x1fed }, { 0xa800000301, 0x385 }, { 0xa800000342, 0x1fc1 }, { 0xc200000300, 0x1ea6 }, { 0xc200000301, 0x1ea4 }, { 0xc200000303, 0x1eaa }, { 0xc200000309, 0x1ea8 }, { 0xc400000304, 0x1de }, { 0xc500000301, 0x1fa }, { 0xc600000301, 0x1fc }, { 0xc600000304, 0x1e2 }, { 0xc700000301, 0x1e08 }, { 0xca00000300, 0x1ec0 }, { 0xca00000301, 0x1ebe }, { 0xca00000303, 0x1ec4 }, { 0xca00000309, 0x1ec2 }, { 0xcf00000301, 0x1e2e }, { 0xd400000300, 0x1ed2 }, { 0xd400000301, 0x1ed0 }, { 0xd400000303, 0x1ed6 }, { 0xd400000309, 0x1ed4 }, { 0xd500000301, 0x1e4c }, { 0xd500000304, 0x22c }, { 0xd500000308, 0x1e4e }, { 0xd600000304, 0x22a }, { 0xd800000301, 0x1fe }, { 0xdc00000300, 0x1db }, { 0xdc00000301, 0x1d7 }, { 0xdc00000304, 0x1d5 }, { 0xdc0000030c, 0x1d9 }, { 0xe200000300, 0x1ea7 }, { 0xe200000301, 0x1ea5 }, { 0xe200000303, 0x1eab }, { 0xe200000309, 0x1ea9 }, { 0xe400000304, 0x1df }, { 0xe500000301, 0x1fb }, { 0xe600000301, 0x1fd }, { 0xe600000304, 0x1e3 }, { 0xe700000301, 0x1e09 }, { 0xea00000300, 0x1ec1 }, { 0xea00000301, 0x1ebf }, { 0xea00000303, 0x1ec5 }, { 0xea00000309, 0x1ec3 }, { 0xef00000301, 0x1e2f }, { 0xf400000300, 0x1ed3 }, { 0xf400000301, 0x1ed1 }, { 0xf400000303, 0x1ed7 }, { 0xf400000309, 0x1ed5 }, { 0xf500000301, 0x1e4d }, { 0xf500000304, 0x22d }, { 0xf500000308, 0x1e4f }, { 0xf600000304, 0x22b }, { 0xf800000301, 0x1ff }, { 0xfc00000300, 0x1dc }, { 0xfc00000301, 0x1d8 }, { 0xfc00000304, 0x1d6 }, { 0xfc0000030c, 0x1da }, { 0x10200000300, 0x1eb0 }, { 0x10200000301, 0x1eae }, { 0x10200000303, 0x1eb4 }, { 0x10200000309, 0x1eb2 }, { 0x10300000300, 0x1eb1 }, { 0x10300000301, 0x1eaf }, { 0x10300000303, 0x1eb5 }, { 0x10300000309, 0x1eb3 }, { 0x11200000300, 0x1e14 }, { 0x11200000301, 0x1e16 }, { 0x11300000300, 0x1e15 }, { 0x11300000301, 0x1e17 }, { 0x14c00000300, 0x1e50 }, { 0x14c00000301, 0x1e52 }, { 0x14d00000300, 0x1e51 }, { 0x14d00000301, 0x1e53 }, { 0x15a00000307, 0x1e64 }, { 0x15b00000307, 0x1e65 }, { 0x16000000307, 0x1e66 }, { 0x16100000307, 0x1e67 }, { 0x16800000301, 0x1e78 }, { 0x16900000301, 0x1e79 }, { 0x16a00000308, 0x1e7a }, { 0x16b00000308, 0x1e7b }, { 0x17f00000307, 0x1e9b }, { 0x1a000000300, 0x1edc }, { 0x1a000000301, 0x1eda }, { 0x1a000000303, 0x1ee0 }, { 0x1a000000309, 0x1ede }, { 0x1a000000323, 0x1ee2 }, { 0x1a100000300, 0x1edd }, { 0x1a100000301, 0x1edb }, { 0x1a100000303, 0x1ee1 }, { 0x1a100000309, 0x1edf }, { 0x1a100000323, 0x1ee3 }, { 0x1af00000300, 0x1eea }, { 0x1af00000301, 0x1ee8 }, { 0x1af00000303, 0x1eee }, { 0x1af00000309, 0x1eec }, { 0x1af00000323, 0x1ef0 }, { 0x1b000000300, 0x1eeb }, { 0x1b000000301, 0x1ee9 }, { 0x1b000000303, 0x1eef }, { 0x1b000000309, 0x1eed }, { 0x1b000000323, 0x1ef1 }, { 0x1b70000030c, 0x1ee }, { 0x1ea00000304, 0x1ec }, { 0x1eb00000304, 0x1ed }, { 0x22600000304, 0x1e0 }, { 0x22700000304, 0x1e1 }, { 0x22800000306, 0x1e1c }, { 0x22900000306, 0x1e1d }, { 0x22e00000304, 0x230 }, { 0x22f00000304, 0x231 }, { 0x2920000030c, 0x1ef }, { 0x39100000300, 0x1fba }, { 0x39100000301, 0x386 }, { 0x39100000304, 0x1fb9 }, { 0x39100000306, 0x1fb8 }, { 0x39100000313, 0x1f08 }, { 0x39100000314, 0x1f09 }, { 0x39100000345, 0x1fbc }, { 0x39500000300, 0x1fc8 }, { 0x39500000301, 0x388 }, { 0x39500000313, 0x1f18 }, { 0x39500000314, 0x1f19 }, { 0x39700000300, 0x1fca }, { 0x39700000301, 0x389 }, { 0x39700000313, 0x1f28 }, { 0x39700000314, 0x1f29 }, { 0x39700000345, 0x1fcc }, { 0x39900000300, 0x1fda }, { 0x39900000301, 0x38a }, { 0x39900000304, 0x1fd9 }, { 0x39900000306, 0x1fd8 }, { 0x39900000308, 0x3aa }, { 0x39900000313, 0x1f38 }, { 0x39900000314, 0x1f39 }, { 0x39f00000300, 0x1ff8 }, { 0x39f00000301, 0x38c }, { 0x39f00000313, 0x1f48 }, { 0x39f00000314, 0x1f49 }, { 0x3a100000314, 0x1fec }, { 0x3a500000300, 0x1fea }, { 0x3a500000301, 0x38e }, { 0x3a500000304, 0x1fe9 }, { 0x3a500000306, 0x1fe8 }, { 0x3a500000308, 0x3ab }, { 0x3a500000314, 0x1f59 }, { 0x3a900000300, 0x1ffa }, { 0x3a900000301, 0x38f }, { 0x3a900000313, 0x1f68 }, { 0x3a900000314, 0x1f69 }, { 0x3a900000345, 0x1ffc }, { 0x3ac00000345, 0x1fb4 }, { 0x3ae00000345, 0x1fc4 }, { 0x3b100000300, 0x1f70 }, { 0x3b100000301, 0x3ac }, { 0x3b100000304, 0x1fb1 }, { 0x3b100000306, 0x1fb0 }, { 0x3b100000313, 0x1f00 }, { 0x3b100000314, 0x1f01 }, { 0x3b100000342, 0x1fb6 }, { 0x3b100000345, 0x1fb3 }, { 0x3b500000300, 0x1f72 }, { 0x3b500000301, 0x3ad }, { 0x3b500000313, 0x1f10 }, { 0x3b500000314, 0x1f11 }, { 0x3b700000300, 0x1f74 }, { 0x3b700000301, 0x3ae }, { 0x3b700000313, 0x1f20 }, { 0x3b700000314, 0x1f21 }, { 0x3b700000342, 0x1fc6 }, { 0x3b700000345, 0x1fc3 }, { 0x3b900000300, 0x1f76 }, { 0x3b900000301, 0x3af }, { 0x3b900000304, 0x1fd1 }, { 0x3b900000306, 0x1fd0 }, { 0x3b900000308, 0x3ca }, { 0x3b900000313, 0x1f30 }, { 0x3b900000314, 0x1f31 }, { 0x3b900000342, 0x1fd6 }, { 0x3bf00000300, 0x1f78 }, { 0x3bf00000301, 0x3cc }, { 0x3bf00000313, 0x1f40 }, { 0x3bf00000314, 0x1f41 }, { 0x3c100000313, 0x1fe4 }, { 0x3c100000314, 0x1fe5 }, { 0x3c500000300, 0x1f7a }, { 0x3c500000301, 0x3cd }, { 0x3c500000304, 0x1fe1 }, { 0x3c500000306, 0x1fe0 }, { 0x3c500000308, 0x3cb }, { 0x3c500000313, 0x1f50 }, { 0x3c500000314, 0x1f51 }, { 0x3c500000342, 0x1fe6 }, { 0x3c900000300, 0x1f7c }, { 0x3c900000301, 0x3ce }, { 0x3c900000313, 0x1f60 }, { 0x3c900000314, 0x1f61 }, { 0x3c900000342, 0x1ff6 }, { 0x3c900000345, 0x1ff3 }, { 0x3ca00000300, 0x1fd2 }, { 0x3ca00000301, 0x390 }, { 0x3ca00000342, 0x1fd7 }, { 0x3cb00000300, 0x1fe2 }, { 0x3cb00000301, 0x3b0 }, { 0x3cb00000342, 0x1fe7 }, { 0x3ce00000345, 0x1ff4 }, { 0x3d200000301, 0x3d3 }, { 0x3d200000308, 0x3d4 }, { 0x40600000308, 0x407 }, { 0x41000000306, 0x4d0 }, { 0x41000000308, 0x4d2 }, { 0x41300000301, 0x403 }, { 0x41500000300, 0x400 }, { 0x41500000306, 0x4d6 }, { 0x41500000308, 0x401 }, { 0x41600000306, 0x4c1 }, { 0x41600000308, 0x4dc }, { 0x41700000308, 0x4de }, { 0x41800000300, 0x40d }, { 0x41800000304, 0x4e2 }, { 0x41800000306, 0x419 }, { 0x41800000308, 0x4e4 }, { 0x41a00000301, 0x40c }, { 0x41e00000308, 0x4e6 }, { 0x42300000304, 0x4ee }, { 0x42300000306, 0x40e }, { 0x42300000308, 0x4f0 }, { 0x4230000030b, 0x4f2 }, { 0x42700000308, 0x4f4 }, { 0x42b00000308, 0x4f8 }, { 0x42d00000308, 0x4ec }, { 0x43000000306, 0x4d1 }, { 0x43000000308, 0x4d3 }, { 0x43300000301, 0x453 }, { 0x43500000300, 0x450 }, { 0x43500000306, 0x4d7 }, { 0x43500000308, 0x451 }, { 0x43600000306, 0x4c2 }, { 0x43600000308, 0x4dd }, { 0x43700000308, 0x4df }, { 0x43800000300, 0x45d }, { 0x43800000304, 0x4e3 }, { 0x43800000306, 0x439 }, { 0x43800000308, 0x4e5 }, { 0x43a00000301, 0x45c }, { 0x43e00000308, 0x4e7 }, { 0x44300000304, 0x4ef }, { 0x44300000306, 0x45e }, { 0x44300000308, 0x4f1 }, { 0x4430000030b, 0x4f3 }, { 0x44700000308, 0x4f5 }, { 0x44b00000308, 0x4f9 }, { 0x44d00000308, 0x4ed }, { 0x45600000308, 0x457 }, { 0x4740000030f, 0x476 }, { 0x4750000030f, 0x477 }, { 0x4d800000308, 0x4da }, { 0x4d900000308, 0x4db }, { 0x4e800000308, 0x4ea }, { 0x4e900000308, 0x4eb }, { 0x62700000653, 0x622 }, { 0x62700000654, 0x623 }, { 0x62700000655, 0x625 }, { 0x64800000654, 0x624 }, { 0x64a00000654, 0x626 }, { 0x6c100000654, 0x6c2 }, { 0x6d200000654, 0x6d3 }, { 0x6d500000654, 0x6c0 }, { 0x9280000093c, 0x929 }, { 0x9300000093c, 0x931 }, { 0x9330000093c, 0x934 }, { 0x9c7000009be, 0x9cb }, { 0x9c7000009d7, 0x9cc }, { 0xb4700000b3e, 0xb4b }, { 0xb4700000b56, 0xb48 }, { 0xb4700000b57, 0xb4c }, { 0xb9200000bd7, 0xb94 }, { 0xbc600000bbe, 0xbca }, { 0xbc600000bd7, 0xbcc }, { 0xbc700000bbe, 0xbcb }, { 0xc4600000c56, 0xc48 }, { 0xcbf00000cd5, 0xcc0 }, { 0xcc600000cc2, 0xcca }, { 0xcc600000cd5, 0xcc7 }, { 0xcc600000cd6, 0xcc8 }, { 0xcca00000cd5, 0xccb }, { 0xd4600000d3e, 0xd4a }, { 0xd4600000d57, 0xd4c }, { 0xd4700000d3e, 0xd4b }, { 0xdd900000dca, 0xdda }, { 0xdd900000dcf, 0xddc }, { 0xdd900000ddf, 0xdde }, { 0xddc00000dca, 0xddd }, { 0x10250000102e, 0x1026 }, { 0x1b0500001b35, 0x1b06 }, { 0x1b0700001b35, 0x1b08 }, { 0x1b0900001b35, 0x1b0a }, { 0x1b0b00001b35, 0x1b0c }, { 0x1b0d00001b35, 0x1b0e }, { 0x1b1100001b35, 0x1b12 }, { 0x1b3a00001b35, 0x1b3b }, { 0x1b3c00001b35, 0x1b3d }, { 0x1b3e00001b35, 0x1b40 }, { 0x1b3f00001b35, 0x1b41 }, { 0x1b4200001b35, 0x1b43 }, { 0x1e3600000304, 0x1e38 }, { 0x1e3700000304, 0x1e39 }, { 0x1e5a00000304, 0x1e5c }, { 0x1e5b00000304, 0x1e5d }, { 0x1e6200000307, 0x1e68 }, { 0x1e6300000307, 0x1e69 }, { 0x1ea000000302, 0x1eac }, { 0x1ea000000306, 0x1eb6 }, { 0x1ea100000302, 0x1ead }, { 0x1ea100000306, 0x1eb7 }, { 0x1eb800000302, 0x1ec6 }, { 0x1eb900000302, 0x1ec7 }, { 0x1ecc00000302, 0x1ed8 }, { 0x1ecd00000302, 0x1ed9 }, { 0x1f0000000300, 0x1f02 }, { 0x1f0000000301, 0x1f04 }, { 0x1f0000000342, 0x1f06 }, { 0x1f0000000345, 0x1f80 }, { 0x1f0100000300, 0x1f03 }, { 0x1f0100000301, 0x1f05 }, { 0x1f0100000342, 0x1f07 }, { 0x1f0100000345, 0x1f81 }, { 0x1f0200000345, 0x1f82 }, { 0x1f0300000345, 0x1f83 }, { 0x1f0400000345, 0x1f84 }, { 0x1f0500000345, 0x1f85 }, { 0x1f0600000345, 0x1f86 }, { 0x1f0700000345, 0x1f87 }, { 0x1f0800000300, 0x1f0a }, { 0x1f0800000301, 0x1f0c }, { 0x1f0800000342, 0x1f0e }, { 0x1f0800000345, 0x1f88 }, { 0x1f0900000300, 0x1f0b }, { 0x1f0900000301, 0x1f0d }, { 0x1f0900000342, 0x1f0f }, { 0x1f0900000345, 0x1f89 }, { 0x1f0a00000345, 0x1f8a }, { 0x1f0b00000345, 0x1f8b }, { 0x1f0c00000345, 0x1f8c }, { 0x1f0d00000345, 0x1f8d }, { 0x1f0e00000345, 0x1f8e }, { 0x1f0f00000345, 0x1f8f }, { 0x1f1000000300, 0x1f12 }, { 0x1f1000000301, 0x1f14 }, { 0x1f1100000300, 0x1f13 }, { 0x1f1100000301, 0x1f15 }, { 0x1f1800000300, 0x1f1a }, { 0x1f1800000301, 0x1f1c }, { 0x1f1900000300, 0x1f1b }, { 0x1f1900000301, 0x1f1d }, { 0x1f2000000300, 0x1f22 }, { 0x1f2000000301, 0x1f24 }, { 0x1f2000000342, 0x1f26 }, { 0x1f2000000345, 0x1f90 }, { 0x1f2100000300, 0x1f23 }, { 0x1f2100000301, 0x1f25 }, { 0x1f2100000342, 0x1f27 }, { 0x1f2100000345, 0x1f91 }, { 0x1f2200000345, 0x1f92 }, { 0x1f2300000345, 0x1f93 }, { 0x1f2400000345, 0x1f94 }, { 0x1f2500000345, 0x1f95 }, { 0x1f2600000345, 0x1f96 }, { 0x1f2700000345, 0x1f97 }, { 0x1f2800000300, 0x1f2a }, { 0x1f2800000301, 0x1f2c }, { 0x1f2800000342, 0x1f2e }, { 0x1f2800000345, 0x1f98 }, { 0x1f2900000300, 0x1f2b }, { 0x1f2900000301, 0x1f2d }, { 0x1f2900000342, 0x1f2f }, { 0x1f2900000345, 0x1f99 }, { 0x1f2a00000345, 0x1f9a }, { 0x1f2b00000345, 0x1f9b }, { 0x1f2c00000345, 0x1f9c }, { 0x1f2d00000345, 0x1f9d }, { 0x1f2e00000345, 0x1f9e }, { 0x1f2f00000345, 0x1f9f }, { 0x1f3000000300, 0x1f32 }, { 0x1f3000000301, 0x1f34 }, { 0x1f3000000342, 0x1f36 }, { 0x1f3100000300, 0x1f33 }, { 0x1f3100000301, 0x1f35 }, { 0x1f3100000342, 0x1f37 }, { 0x1f3800000300, 0x1f3a }, { 0x1f3800000301, 0x1f3c }, { 0x1f3800000342, 0x1f3e }, { 0x1f3900000300, 0x1f3b }, { 0x1f3900000301, 0x1f3d }, { 0x1f3900000342, 0x1f3f }, { 0x1f4000000300, 0x1f42 }, { 0x1f4000000301, 0x1f44 }, { 0x1f4100000300, 0x1f43 }, { 0x1f4100000301, 0x1f45 }, { 0x1f4800000300, 0x1f4a }, { 0x1f4800000301, 0x1f4c }, { 0x1f4900000300, 0x1f4b }, { 0x1f4900000301, 0x1f4d }, { 0x1f5000000300, 0x1f52 }, { 0x1f5000000301, 0x1f54 }, { 0x1f5000000342, 0x1f56 }, { 0x1f5100000300, 0x1f53 }, { 0x1f5100000301, 0x1f55 }, { 0x1f5100000342, 0x1f57 }, { 0x1f5900000300, 0x1f5b }, { 0x1f5900000301, 0x1f5d }, { 0x1f5900000342, 0x1f5f }, { 0x1f6000000300, 0x1f62 }, { 0x1f6000000301, 0x1f64 }, { 0x1f6000000342, 0x1f66 }, { 0x1f6000000345, 0x1fa0 }, { 0x1f6100000300, 0x1f63 }, { 0x1f6100000301, 0x1f65 }, { 0x1f6100000342, 0x1f67 }, { 0x1f6100000345, 0x1fa1 }, { 0x1f6200000345, 0x1fa2 }, { 0x1f6300000345, 0x1fa3 }, { 0x1f6400000345, 0x1fa4 }, { 0x1f6500000345, 0x1fa5 }, { 0x1f6600000345, 0x1fa6 }, { 0x1f6700000345, 0x1fa7 }, { 0x1f6800000300, 0x1f6a }, { 0x1f6800000301, 0x1f6c }, { 0x1f6800000342, 0x1f6e }, { 0x1f6800000345, 0x1fa8 }, { 0x1f6900000300, 0x1f6b }, { 0x1f6900000301, 0x1f6d }, { 0x1f6900000342, 0x1f6f }, { 0x1f6900000345, 0x1fa9 }, { 0x1f6a00000345, 0x1faa }, { 0x1f6b00000345, 0x1fab }, { 0x1f6c00000345, 0x1fac }, { 0x1f6d00000345, 0x1fad }, { 0x1f6e00000345, 0x1fae }, { 0x1f6f00000345, 0x1faf }, { 0x1f7000000345, 0x1fb2 }, { 0x1f7400000345, 0x1fc2 }, { 0x1f7c00000345, 0x1ff2 }, { 0x1fb600000345, 0x1fb7 }, { 0x1fbf00000300, 0x1fcd }, { 0x1fbf00000301, 0x1fce }, { 0x1fbf00000342, 0x1fcf }, { 0x1fc600000345, 0x1fc7 }, { 0x1ff600000345, 0x1ff7 }, { 0x1ffe00000300, 0x1fdd }, { 0x1ffe00000301, 0x1fde }, { 0x1ffe00000342, 0x1fdf }, { 0x219000000338, 0x219a }, { 0x219200000338, 0x219b }, { 0x219400000338, 0x21ae }, { 0x21d000000338, 0x21cd }, { 0x21d200000338, 0x21cf }, { 0x21d400000338, 0x21ce }, { 0x220300000338, 0x2204 }, { 0x220800000338, 0x2209 }, { 0x220b00000338, 0x220c }, { 0x222300000338, 0x2224 }, { 0x222500000338, 0x2226 }, { 0x223c00000338, 0x2241 }, { 0x224300000338, 0x2244 }, { 0x224500000338, 0x2247 }, { 0x224800000338, 0x2249 }, { 0x224d00000338, 0x226d }, { 0x226100000338, 0x2262 }, { 0x226400000338, 0x2270 }, { 0x226500000338, 0x2271 }, { 0x227200000338, 0x2274 }, { 0x227300000338, 0x2275 }, { 0x227600000338, 0x2278 }, { 0x227700000338, 0x2279 }, { 0x227a00000338, 0x2280 }, { 0x227b00000338, 0x2281 }, { 0x227c00000338, 0x22e0 }, { 0x227d00000338, 0x22e1 }, { 0x228200000338, 0x2284 }, { 0x228300000338, 0x2285 }, { 0x228600000338, 0x2288 }, { 0x228700000338, 0x2289 }, { 0x229100000338, 0x22e2 }, { 0x229200000338, 0x22e3 }, { 0x22a200000338, 0x22ac }, { 0x22a800000338, 0x22ad }, { 0x22a900000338, 0x22ae }, { 0x22ab00000338, 0x22af }, { 0x22b200000338, 0x22ea }, { 0x22b300000338, 0x22eb }, { 0x22b400000338, 0x22ec }, { 0x22b500000338, 0x22ed }, { 0x304600003099, 0x3094 }, { 0x304b00003099, 0x304c }, { 0x304d00003099, 0x304e }, { 0x304f00003099, 0x3050 }, { 0x305100003099, 0x3052 }, { 0x305300003099, 0x3054 }, { 0x305500003099, 0x3056 }, { 0x305700003099, 0x3058 }, { 0x305900003099, 0x305a }, { 0x305b00003099, 0x305c }, { 0x305d00003099, 0x305e }, { 0x305f00003099, 0x3060 }, { 0x306100003099, 0x3062 }, { 0x306400003099, 0x3065 }, { 0x306600003099, 0x3067 }, { 0x306800003099, 0x3069 }, { 0x306f00003099, 0x3070 }, { 0x306f0000309a, 0x3071 }, { 0x307200003099, 0x3073 }, { 0x30720000309a, 0x3074 }, { 0x307500003099, 0x3076 }, { 0x30750000309a, 0x3077 }, { 0x307800003099, 0x3079 }, { 0x30780000309a, 0x307a }, { 0x307b00003099, 0x307c }, { 0x307b0000309a, 0x307d }, { 0x309d00003099, 0x309e }, { 0x30a600003099, 0x30f4 }, { 0x30ab00003099, 0x30ac }, { 0x30ad00003099, 0x30ae }, { 0x30af00003099, 0x30b0 }, { 0x30b100003099, 0x30b2 }, { 0x30b300003099, 0x30b4 }, { 0x30b500003099, 0x30b6 }, { 0x30b700003099, 0x30b8 }, { 0x30b900003099, 0x30ba }, { 0x30bb00003099, 0x30bc }, { 0x30bd00003099, 0x30be }, { 0x30bf00003099, 0x30c0 }, { 0x30c100003099, 0x30c2 }, { 0x30c400003099, 0x30c5 }, { 0x30c600003099, 0x30c7 }, { 0x30c800003099, 0x30c9 }, { 0x30cf00003099, 0x30d0 }, { 0x30cf0000309a, 0x30d1 }, { 0x30d200003099, 0x30d3 }, { 0x30d20000309a, 0x30d4 }, { 0x30d500003099, 0x30d6 }, { 0x30d50000309a, 0x30d7 }, { 0x30d800003099, 0x30d9 }, { 0x30d80000309a, 0x30da }, { 0x30db00003099, 0x30dc }, { 0x30db0000309a, 0x30dd }, { 0x30ef00003099, 0x30f7 }, { 0x30f000003099, 0x30f8 }, { 0x30f100003099, 0x30f9 }, { 0x30f200003099, 0x30fa }, { 0x30fd00003099, 0x30fe }, { 0x11099000110ba, 0x1109a }, { 0x1109b000110ba, 0x1109c }, { 0x110a5000110ba, 0x110ab }, { 0x1113100011127, 0x1112e }, { 0x1113200011127, 0x1112f }, { 0x113470001133e, 0x1134b }, { 0x1134700011357, 0x1134c }, { 0x114b9000114b0, 0x114bc }, { 0x114b9000114ba, 0x114bb }, { 0x114b9000114bd, 0x114be }, { 0x115b8000115af, 0x115ba }, { 0x115b9000115af, 0x115bb }, }; const CompositionRecord* UnicodeCompositionRecordPtr = UnicodeCompositionRecord; const char* CompressedStringData = "\x41\xCC\x80\x41\xCC\x81\x41\xCC\x82\x41\xCC\x83\x41\xCC\x88\x41\xCC\x8A\x43\xCC\xA7\x45\xCC\x80\x45" "\xCC\x81\x45\xCC\x82\x45\xCC\x88\x49\xCC\x80\x49\xCC\x81\x49\xCC\x82\x49\xCC\x88\x4E\xCC\x83\x4F\xCC" "\x80\x4F\xCC\x81\x4F\xCC\x82\x4F\xCC\x83\x4F\xCC\x88\x55\xCC\x80\x55\xCC\x81\x55\xCC\x82\x55\xCC\x88" "\x59\xCC\x81\x61\xCC\x80\x61\xCC\x81\x61\xCC\x82\x61\xCC\x83\x61\xCC\x88\x61\xCC\x8A\x63\xCC\xA7\x65" "\xCC\x80\x65\xCC\x81\x65\xCC\x82\x65\xCC\x88\x69\xCC\x80\x69\xCC\x81\x69\xCC\x82\x69\xCC\x88\x6E\xCC" "\x83\x6F\xCC\x80\x6F\xCC\x81\x6F\xCC\x82\x6F\xCC\x83\x6F\xCC\x88\x75\xCC\x80\x75\xCC\x81\x75\xCC\x82" "\x75\xCC\x88\x79\xCC\x81\x79\xCC\x88\x41\xCC\x84\x61\xCC\x84\x41\xCC\x86\x61\xCC\x86\x41\xCC\xA8\x61" "\xCC\xA8\x43\xCC\x81\x63\xCC\x81\x43\xCC\x82\x63\xCC\x82\x43\xCC\x87\x63\xCC\x87\x43\xCC\x8C\x63\xCC" "\x8C\x44\xCC\x8C\x64\xCC\x8C\x45\xCC\x84\x65\xCC\x84\x45\xCC\x86\x65\xCC\x86\x45\xCC\x87\x65\xCC\x87" "\x45\xCC\xA8\x65\xCC\xA8\x45\xCC\x8C\x65\xCC\x8C\x47\xCC\x82\x67\xCC\x82\x47\xCC\x86\x67\xCC\x86\x47" "\xCC\x87\x67\xCC\x87\x47\xCC\xA7\x67\xCC\xA7\x48\xCC\x82\x68\xCC\x82\x49\xCC\x83\x69\xCC\x83\x49\xCC" "\x84\x69\xCC\x84\x49\xCC\x86\x69\xCC\x86\x49\xCC\xA8\x69\xCC\xA8\x49\xCC\x87\x4A\xCC\x82\x6A\xCC\x82" "\x4B\xCC\xA7\x6B\xCC\xA7\x4C\xCC\x81\x6C\xCC\x81\x4C\xCC\xA7\x6C\xCC\xA7\x4C\xCC\x8C\x6C\xCC\x8C\x4E" "\xCC\x81\x6E\xCC\x81\x4E\xCC\xA7\x6E\xCC\xA7\x4E\xCC\x8C\x6E\xCC\x8C\x4F\xCC\x84\x6F\xCC\x84\x4F\xCC" "\x86\x6F\xCC\x86\x4F\xCC\x8B\x6F\xCC\x8B\x52\xCC\x81\x72\xCC\x81\x52\xCC\xA7\x72\xCC\xA7\x52\xCC\x8C" "\x72\xCC\x8C\x53\xCC\x81\x73\xCC\x81\x53\xCC\x82\x73\xCC\x82\x53\xCC\xA7\x73\xCC\xA7\x53\xCC\x8C\x73" "\xCC\x8C\x54\xCC\xA7\x74\xCC\xA7\x54\xCC\x8C\x74\xCC\x8C\x55\xCC\x83\x75\xCC\x83\x55\xCC\x84\x75\xCC" "\x84\x55\xCC\x86\x75\xCC\x86\x55\xCC\x8A\x75\xCC\x8A\x55\xCC\x8B\x75\xCC\x8B\x55\xCC\xA8\x75\xCC\xA8" "\x57\xCC\x82\x77\xCC\x82\x59\xCC\x82\x79\xCC\x82\x59\xCC\x88\x5A\xCC\x81\x7A\xCC\x81\x5A\xCC\x87\x7A" "\xCC\x87\x5A\xCC\x8C\x7A\xCC\x8C\x4F\xCC\x9B\x6F\xCC\x9B\x55\xCC\x9B\x75\xCC\x9B\x41\xCC\x8C\x61\xCC" "\x8C\x49\xCC\x8C\x69\xCC\x8C\x4F\xCC\x8C\x6F\xCC\x8C\x55\xCC\x8C\x75\xCC\x8C\x55\xCC\x88\xCC\x84\x75" "\xCC\x88\xCC\x84\x55\xCC\x88\xCC\x81\x75\xCC\x88\xCC\x81\x55\xCC\x88\xCC\x8C\x75\xCC\x88\xCC\x8C\x55" "\xCC\x88\xCC\x80\x75\xCC\x88\xCC\x80\x41\xCC\x88\xCC\x84\x61\xCC\x88\xCC\x84\x41\xCC\x87\xCC\x84\x61" "\xCC\x87\xCC\x84\xC3\x86\xCC\x84\xC3\xA6\xCC\x84\x47\xCC\x8C\x67\xCC\x8C\x4B\xCC\x8C\x6B\xCC\x8C\x4F" "\xCC\xA8\x6F\xCC\xA8\x4F\xCC\xA8\xCC\x84\x6F\xCC\xA8\xCC\x84\xC6\xB7\xCC\x8C\xCA\x92\xCC\x8C\x6A\xCC" "\x8C\x47\xCC\x81\x67\xCC\x81\x4E\xCC\x80\x6E\xCC\x80\x41\xCC\x8A\xCC\x81\x61\xCC\x8A\xCC\x81\xC3\x86" "\xCC\x81\xC3\xA6\xCC\x81\xC3\x98\xCC\x81\xC3\xB8\xCC\x81\x41\xCC\x8F\x61\xCC\x8F\x41\xCC\x91\x61\xCC" "\x91\x45\xCC\x8F\x65\xCC\x8F\x45\xCC\x91\x65\xCC\x91\x49\xCC\x8F\x69\xCC\x8F\x49\xCC\x91\x69\xCC\x91" "\x4F\xCC\x8F\x6F\xCC\x8F\x4F\xCC\x91\x6F\xCC\x91\x52\xCC\x8F\x72\xCC\x8F\x52\xCC\x91\x72\xCC\x91\x55" "\xCC\x8F\x75\xCC\x8F\x55\xCC\x91\x75\xCC\x91\x53\xCC\xA6\x73\xCC\xA6\x54\xCC\xA6\x74\xCC\xA6\x48\xCC" "\x8C\x68\xCC\x8C\x45\xCC\xA7\x65\xCC\xA7\x4F\xCC\x88\xCC\x84\x6F\xCC\x88\xCC\x84\x4F\xCC\x83\xCC\x84" "\x6F\xCC\x83\xCC\x84\x4F\xCC\x87\x6F\xCC\x87\x4F\xCC\x87\xCC\x84\x6F\xCC\x87\xCC\x84\x59\xCC\x84\x79" "\xCC\x84\xCC\x93\xCA\xB9\x3B\xC2\xA8\xCC\x81\xCE\x91\xCC\x81\xC2\xB7\xCE\x95\xCC\x81\xCE\x97\xCC\x81" "\xCE\x99\xCC\x81\xCE\x9F\xCC\x81\xCE\xA5\xCC\x81\xCE\xA9\xCC\x81\xCE\xB9\xCC\x88\xCC\x81\xCE\x99\xCC" "\x88\xCE\xA5\xCC\x88\xCE\xB1\xCC\x81\xCE\xB5\xCC\x81\xCE\xB7\xCC\x81\xCE\xB9\xCC\x81\xCF\x85\xCC\x88" "\xCC\x81\xCE\xBF\xCC\x81\xCF\x85\xCC\x81\xCF\x89\xCC\x81\xCF\x92\xCC\x81\xCF\x92\xCC\x88\xD0\x95\xCC" "\x80\xD0\x95\xCC\x88\xD0\x93\xCC\x81\xD0\x86\xCC\x88\xD0\x9A\xCC\x81\xD0\x98\xCC\x80\xD0\xA3\xCC\x86" "\xD0\x98\xCC\x86\xD0\xB8\xCC\x86\xD0\xB5\xCC\x80\xD0\xB5\xCC\x88\xD0\xB3\xCC\x81\xD1\x96\xCC\x88\xD0" "\xBA\xCC\x81\xD0\xB8\xCC\x80\xD1\x83\xCC\x86\xD1\xB4\xCC\x8F\xD1\xB5\xCC\x8F\xD0\x96\xCC\x86\xD0\xB6" "\xCC\x86\xD0\x90\xCC\x86\xD0\xB0\xCC\x86\xD0\x90\xCC\x88\xD0\xB0\xCC\x88\xD0\x95\xCC\x86\xD0\xB5\xCC" "\x86\xD3\x98\xCC\x88\xD3\x99\xCC\x88\xD0\x96\xCC\x88\xD0\xB6\xCC\x88\xD0\x97\xCC\x88\xD0\xB7\xCC\x88" "\xD0\x98\xCC\x84\xD0\xB8\xCC\x84\xD0\x98\xCC\x88\xD0\xB8\xCC\x88\xD0\x9E\xCC\x88\xD0\xBE\xCC\x88\xD3" "\xA8\xCC\x88\xD3\xA9\xCC\x88\xD0\xAD\xCC\x88\xD1\x8D\xCC\x88\xD0\xA3\xCC\x84\xD1\x83\xCC\x84\xD0\xA3" "\xCC\x88\xD1\x83\xCC\x88\xD0\xA3\xCC\x8B\xD1\x83\xCC\x8B\xD0\xA7\xCC\x88\xD1\x87\xCC\x88\xD0\xAB\xCC" "\x88\xD1\x8B\xCC\x88\xD8\xA7\xD9\x93\xD8\xA7\xD9\x94\xD9\x88\xD9\x94\xD8\xA7\xD9\x95\xD9\x8A\xD9\x94" "\xDB\x95\xD9\x94\xDB\x81\xD9\x94\xDB\x92\xD9\x94\xE0\xA4\xA8\xE0\xA4\xBC\xE0\xA4\xB0\xE0\xA4\xBC\xE0" "\xA4\xB3\xE0\xA4\xBC\xE0\xA4\x95\xE0\xA4\xBC\xE0\xA4\x96\xE0\xA4\xBC\xE0\xA4\x97\xE0\xA4\xBC\xE0\xA4" "\x9C\xE0\xA4\xBC\xE0\xA4\xA1\xE0\xA4\xBC\xE0\xA4\xA2\xE0\xA4\xBC\xE0\xA4\xAB\xE0\xA4\xBC\xE0\xA4\xAF" "\xE0\xA4\xBC\xE0\xA7\x87\xE0\xA6\xBE\xE0\xA7\x87\xE0\xA7\x97\xE0\xA6\xA1\xE0\xA6\xBC\xE0\xA6\xA2\xE0" "\xA6\xBC\xE0\xA6\xAF\xE0\xA6\xBC\xE0\xA8\xB2\xE0\xA8\xBC\xE0\xA8\xB8\xE0\xA8\xBC\xE0\xA8\x96\xE0\xA8" "\xBC\xE0\xA8\x97\xE0\xA8\xBC\xE0\xA8\x9C\xE0\xA8\xBC\xE0\xA8\xAB\xE0\xA8\xBC\xE0\xAD\x87\xE0\xAD\x96" "\xE0\xAD\x87\xE0\xAC\xBE\xE0\xAD\x87\xE0\xAD\x97\xE0\xAC\xA1\xE0\xAC\xBC\xE0\xAC\xA2\xE0\xAC\xBC\xE0" "\xAE\x92\xE0\xAF\x97\xE0\xAF\x86\xE0\xAE\xBE\xE0\xAF\x87\xE0\xAE\xBE\xE0\xAF\x86\xE0\xAF\x97\xE0\xB1" "\x86\xE0\xB1\x96\xE0\xB2\xBF\xE0\xB3\x95\xE0\xB3\x86\xE0\xB3\x95\xE0\xB3\x86\xE0\xB3\x96\xE0\xB3\x86" "\xE0\xB3\x82\xE0\xB3\x86\xE0\xB3\x82\xE0\xB3\x95\xE0\xB5\x86\xE0\xB4\xBE\xE0\xB5\x87\xE0\xB4\xBE\xE0" "\xB5\x86\xE0\xB5\x97\xE0\xB7\x99\xE0\xB7\x8A\xE0\xB7\x99\xE0\xB7\x8F\xE0\xB7\x99\xE0\xB7\x8F\xE0\xB7" "\x8A\xE0\xB7\x99\xE0\xB7\x9F\xE0\xBD\x82\xE0\xBE\xB7\xE0\xBD\x8C\xE0\xBE\xB7\xE0\xBD\x91\xE0\xBE\xB7" "\xE0\xBD\x96\xE0\xBE\xB7\xE0\xBD\x9B\xE0\xBE\xB7\xE0\xBD\x80\xE0\xBE\xB5\xE0\xBD\xB1\xE0\xBD\xB2\xE0" "\xBD\xB1\xE0\xBD\xB4\xE0\xBE\xB2\xE0\xBE\x80\xE0\xBE\xB3\xE0\xBE\x80\xE0\xBD\xB1\xE0\xBE\x80\xE0\xBE" "\x92\xE0\xBE\xB7\xE0\xBE\x9C\xE0\xBE\xB7\xE0\xBE\xA1\xE0\xBE\xB7\xE0\xBE\xA6\xE0\xBE\xB7\xE0\xBE\xAB" "\xE0\xBE\xB7\xE0\xBE\x90\xE0\xBE\xB5\xE1\x80\xA5\xE1\x80\xAE\xE1\xAC\x85\xE1\xAC\xB5\xE1\xAC\x87\xE1" "\xAC\xB5\xE1\xAC\x89\xE1\xAC\xB5\xE1\xAC\x8B\xE1\xAC\xB5\xE1\xAC\x8D\xE1\xAC\xB5\xE1\xAC\x91\xE1\xAC" "\xB5\xE1\xAC\xBA\xE1\xAC\xB5\xE1\xAC\xBC\xE1\xAC\xB5\xE1\xAC\xBE\xE1\xAC\xB5\xE1\xAC\xBF\xE1\xAC\xB5" "\xE1\xAD\x82\xE1\xAC\xB5\x41\xCC\xA5\x61\xCC\xA5\x42\xCC\x87\x62\xCC\x87\x42\xCC\xA3\x62\xCC\xA3\x42" "\xCC\xB1\x62\xCC\xB1\x43\xCC\xA7\xCC\x81\x63\xCC\xA7\xCC\x81\x44\xCC\x87\x64\xCC\x87\x44\xCC\xA3\x64" "\xCC\xA3\x44\xCC\xB1\x64\xCC\xB1\x44\xCC\xA7\x64\xCC\xA7\x44\xCC\xAD\x64\xCC\xAD\x45\xCC\x84\xCC\x80" "\x65\xCC\x84\xCC\x80\x45\xCC\x84\xCC\x81\x65\xCC\x84\xCC\x81\x45\xCC\xAD\x65\xCC\xAD\x45\xCC\xB0\x65" "\xCC\xB0\x45\xCC\xA7\xCC\x86\x65\xCC\xA7\xCC\x86\x46\xCC\x87\x66\xCC\x87\x47\xCC\x84\x67\xCC\x84\x48" "\xCC\x87\x68\xCC\x87\x48\xCC\xA3\x68\xCC\xA3\x48\xCC\x88\x68\xCC\x88\x48\xCC\xA7\x68\xCC\xA7\x48\xCC" "\xAE\x68\xCC\xAE\x49\xCC\xB0\x69\xCC\xB0\x49\xCC\x88\xCC\x81\x69\xCC\x88\xCC\x81\x4B\xCC\x81\x6B\xCC" "\x81\x4B\xCC\xA3\x6B\xCC\xA3\x4B\xCC\xB1\x6B\xCC\xB1\x4C\xCC\xA3\x6C\xCC\xA3\x4C\xCC\xA3\xCC\x84\x6C" "\xCC\xA3\xCC\x84\x4C\xCC\xB1\x6C\xCC\xB1\x4C\xCC\xAD\x6C\xCC\xAD\x4D\xCC\x81\x6D\xCC\x81\x4D\xCC\x87" "\x6D\xCC\x87\x4D\xCC\xA3\x6D\xCC\xA3\x4E\xCC\x87\x6E\xCC\x87\x4E\xCC\xA3\x6E\xCC\xA3\x4E\xCC\xB1\x6E" "\xCC\xB1\x4E\xCC\xAD\x6E\xCC\xAD\x4F\xCC\x83\xCC\x81\x6F\xCC\x83\xCC\x81\x4F\xCC\x83\xCC\x88\x6F\xCC" "\x83\xCC\x88\x4F\xCC\x84\xCC\x80\x6F\xCC\x84\xCC\x80\x4F\xCC\x84\xCC\x81\x6F\xCC\x84\xCC\x81\x50\xCC" "\x81\x70\xCC\x81\x50\xCC\x87\x70\xCC\x87\x52\xCC\x87\x72\xCC\x87\x52\xCC\xA3\x72\xCC\xA3\x52\xCC\xA3" "\xCC\x84\x72\xCC\xA3\xCC\x84\x52\xCC\xB1\x72\xCC\xB1\x53\xCC\x87\x73\xCC\x87\x53\xCC\xA3\x73\xCC\xA3" "\x53\xCC\x81\xCC\x87\x73\xCC\x81\xCC\x87\x53\xCC\x8C\xCC\x87\x73\xCC\x8C\xCC\x87\x53\xCC\xA3\xCC\x87" "\x73\xCC\xA3\xCC\x87\x54\xCC\x87\x74\xCC\x87\x54\xCC\xA3\x74\xCC\xA3\x54\xCC\xB1\x74\xCC\xB1\x54\xCC" "\xAD\x74\xCC\xAD\x55\xCC\xA4\x75\xCC\xA4\x55\xCC\xB0\x75\xCC\xB0\x55\xCC\xAD\x75\xCC\xAD\x55\xCC\x83" "\xCC\x81\x75\xCC\x83\xCC\x81\x55\xCC\x84\xCC\x88\x75\xCC\x84\xCC\x88\x56\xCC\x83\x76\xCC\x83\x56\xCC" "\xA3\x76\xCC\xA3\x57\xCC\x80\x77\xCC\x80\x57\xCC\x81\x77\xCC\x81\x57\xCC\x88\x77\xCC\x88\x57\xCC\x87" "\x77\xCC\x87\x57\xCC\xA3\x77\xCC\xA3\x58\xCC\x87\x78\xCC\x87\x58\xCC\x88\x78\xCC\x88\x59\xCC\x87\x79" "\xCC\x87\x5A\xCC\x82\x7A\xCC\x82\x5A\xCC\xA3\x7A\xCC\xA3\x5A\xCC\xB1\x7A\xCC\xB1\x68\xCC\xB1\x74\xCC" "\x88\x77\xCC\x8A\x79\xCC\x8A\xC5\xBF\xCC\x87\x41\xCC\xA3\x61\xCC\xA3\x41\xCC\x89\x61\xCC\x89\x41\xCC" "\x82\xCC\x81\x61\xCC\x82\xCC\x81\x41\xCC\x82\xCC\x80\x61\xCC\x82\xCC\x80\x41\xCC\x82\xCC\x89\x61\xCC" "\x82\xCC\x89\x41\xCC\x82\xCC\x83\x61\xCC\x82\xCC\x83\x41\xCC\xA3\xCC\x82\x61\xCC\xA3\xCC\x82\x41\xCC" "\x86\xCC\x81\x61\xCC\x86\xCC\x81\x41\xCC\x86\xCC\x80\x61\xCC\x86\xCC\x80\x41\xCC\x86\xCC\x89\x61\xCC" "\x86\xCC\x89\x41\xCC\x86\xCC\x83\x61\xCC\x86\xCC\x83\x41\xCC\xA3\xCC\x86\x61\xCC\xA3\xCC\x86\x45\xCC" "\xA3\x65\xCC\xA3\x45\xCC\x89\x65\xCC\x89\x45\xCC\x83\x65\xCC\x83\x45\xCC\x82\xCC\x81\x65\xCC\x82\xCC" "\x81\x45\xCC\x82\xCC\x80\x65\xCC\x82\xCC\x80\x45\xCC\x82\xCC\x89\x65\xCC\x82\xCC\x89\x45\xCC\x82\xCC" "\x83\x65\xCC\x82\xCC\x83\x45\xCC\xA3\xCC\x82\x65\xCC\xA3\xCC\x82\x49\xCC\x89\x69\xCC\x89\x49\xCC\xA3" "\x69\xCC\xA3\x4F\xCC\xA3\x6F\xCC\xA3\x4F\xCC\x89\x6F\xCC\x89\x4F\xCC\x82\xCC\x81\x6F\xCC\x82\xCC\x81" "\x4F\xCC\x82\xCC\x80\x6F\xCC\x82\xCC\x80\x4F\xCC\x82\xCC\x89\x6F\xCC\x82\xCC\x89\x4F\xCC\x82\xCC\x83" "\x6F\xCC\x82\xCC\x83\x4F\xCC\xA3\xCC\x82\x6F\xCC\xA3\xCC\x82\x4F\xCC\x9B\xCC\x81\x6F\xCC\x9B\xCC\x81" "\x4F\xCC\x9B\xCC\x80\x6F\xCC\x9B\xCC\x80\x4F\xCC\x9B\xCC\x89\x6F\xCC\x9B\xCC\x89\x4F\xCC\x9B\xCC\x83" "\x6F\xCC\x9B\xCC\x83\x4F\xCC\x9B\xCC\xA3\x6F\xCC\x9B\xCC\xA3\x55\xCC\xA3\x75\xCC\xA3\x55\xCC\x89\x75" "\xCC\x89\x55\xCC\x9B\xCC\x81\x75\xCC\x9B\xCC\x81\x55\xCC\x9B\xCC\x80\x75\xCC\x9B\xCC\x80\x55\xCC\x9B" "\xCC\x89\x75\xCC\x9B\xCC\x89\x55\xCC\x9B\xCC\x83\x75\xCC\x9B\xCC\x83\x55\xCC\x9B\xCC\xA3\x75\xCC\x9B" "\xCC\xA3\x59\xCC\x80\x79\xCC\x80\x59\xCC\xA3\x79\xCC\xA3\x59\xCC\x89\x79\xCC\x89\x59\xCC\x83\x79\xCC" "\x83\xCE\xB1\xCC\x93\xCE\xB1\xCC\x94\xCE\xB1\xCC\x93\xCC\x80\xCE\xB1\xCC\x94\xCC\x80\xCE\xB1\xCC\x93" "\xCC\x81\xCE\xB1\xCC\x94\xCC\x81\xCE\xB1\xCC\x93\xCD\x82\xCE\xB1\xCC\x94\xCD\x82\xCE\x91\xCC\x93\xCE" "\x91\xCC\x94\xCE\x91\xCC\x93\xCC\x80\xCE\x91\xCC\x94\xCC\x80\xCE\x91\xCC\x93\xCC\x81\xCE\x91\xCC\x94" "\xCC\x81\xCE\x91\xCC\x93\xCD\x82\xCE\x91\xCC\x94\xCD\x82\xCE\xB5\xCC\x93\xCE\xB5\xCC\x94\xCE\xB5\xCC" "\x93\xCC\x80\xCE\xB5\xCC\x94\xCC\x80\xCE\xB5\xCC\x93\xCC\x81\xCE\xB5\xCC\x94\xCC\x81\xCE\x95\xCC\x93" "\xCE\x95\xCC\x94\xCE\x95\xCC\x93\xCC\x80\xCE\x95\xCC\x94\xCC\x80\xCE\x95\xCC\x93\xCC\x81\xCE\x95\xCC" "\x94\xCC\x81\xCE\xB7\xCC\x93\xCE\xB7\xCC\x94\xCE\xB7\xCC\x93\xCC\x80\xCE\xB7\xCC\x94\xCC\x80\xCE\xB7" "\xCC\x93\xCC\x81\xCE\xB7\xCC\x94\xCC\x81\xCE\xB7\xCC\x93\xCD\x82\xCE\xB7\xCC\x94\xCD\x82\xCE\x97\xCC" "\x93\xCE\x97\xCC\x94\xCE\x97\xCC\x93\xCC\x80\xCE\x97\xCC\x94\xCC\x80\xCE\x97\xCC\x93\xCC\x81\xCE\x97" "\xCC\x94\xCC\x81\xCE\x97\xCC\x93\xCD\x82\xCE\x97\xCC\x94\xCD\x82\xCE\xB9\xCC\x93\xCE\xB9\xCC\x94\xCE" "\xB9\xCC\x93\xCC\x80\xCE\xB9\xCC\x94\xCC\x80\xCE\xB9\xCC\x93\xCC\x81\xCE\xB9\xCC\x94\xCC\x81\xCE\xB9" "\xCC\x93\xCD\x82\xCE\xB9\xCC\x94\xCD\x82\xCE\x99\xCC\x93\xCE\x99\xCC\x94\xCE\x99\xCC\x93\xCC\x80\xCE" "\x99\xCC\x94\xCC\x80\xCE\x99\xCC\x93\xCC\x81\xCE\x99\xCC\x94\xCC\x81\xCE\x99\xCC\x93\xCD\x82\xCE\x99" "\xCC\x94\xCD\x82\xCE\xBF\xCC\x93\xCE\xBF\xCC\x94\xCE\xBF\xCC\x93\xCC\x80\xCE\xBF\xCC\x94\xCC\x80\xCE" "\xBF\xCC\x93\xCC\x81\xCE\xBF\xCC\x94\xCC\x81\xCE\x9F\xCC\x93\xCE\x9F\xCC\x94\xCE\x9F\xCC\x93\xCC\x80" "\xCE\x9F\xCC\x94\xCC\x80\xCE\x9F\xCC\x93\xCC\x81\xCE\x9F\xCC\x94\xCC\x81\xCF\x85\xCC\x93\xCF\x85\xCC" "\x94\xCF\x85\xCC\x93\xCC\x80\xCF\x85\xCC\x94\xCC\x80\xCF\x85\xCC\x93\xCC\x81\xCF\x85\xCC\x94\xCC\x81" "\xCF\x85\xCC\x93\xCD\x82\xCF\x85\xCC\x94\xCD\x82\xCE\xA5\xCC\x94\xCE\xA5\xCC\x94\xCC\x80\xCE\xA5\xCC" "\x94\xCC\x81\xCE\xA5\xCC\x94\xCD\x82\xCF\x89\xCC\x93\xCF\x89\xCC\x94\xCF\x89\xCC\x93\xCC\x80\xCF\x89" "\xCC\x94\xCC\x80\xCF\x89\xCC\x93\xCC\x81\xCF\x89\xCC\x94\xCC\x81\xCF\x89\xCC\x93\xCD\x82\xCF\x89\xCC" "\x94\xCD\x82\xCE\xA9\xCC\x93\xCE\xA9\xCC\x94\xCE\xA9\xCC\x93\xCC\x80\xCE\xA9\xCC\x94\xCC\x80\xCE\xA9" "\xCC\x93\xCC\x81\xCE\xA9\xCC\x94\xCC\x81\xCE\xA9\xCC\x93\xCD\x82\xCE\xA9\xCC\x94\xCD\x82\xCE\xB1\xCC" "\x80\xCE\xB5\xCC\x80\xCE\xB7\xCC\x80\xCE\xB9\xCC\x80\xCE\xBF\xCC\x80\xCF\x85\xCC\x80\xCF\x89\xCC\x80" "\xCE\xB1\xCC\x93\xCD\x85\xCE\xB1\xCC\x94\xCD\x85\xCE\xB1\xCC\x93\xCC\x80\xCD\x85\xCE\xB1\xCC\x94\xCC" "\x80\xCD\x85\xCE\xB1\xCC\x93\xCC\x81\xCD\x85\xCE\xB1\xCC\x94\xCC\x81\xCD\x85\xCE\xB1\xCC\x93\xCD\x82" "\xCD\x85\xCE\xB1\xCC\x94\xCD\x82\xCD\x85\xCE\x91\xCC\x93\xCD\x85\xCE\x91\xCC\x94\xCD\x85\xCE\x91\xCC" "\x93\xCC\x80\xCD\x85\xCE\x91\xCC\x94\xCC\x80\xCD\x85\xCE\x91\xCC\x93\xCC\x81\xCD\x85\xCE\x91\xCC\x94" "\xCC\x81\xCD\x85\xCE\x91\xCC\x93\xCD\x82\xCD\x85\xCE\x91\xCC\x94\xCD\x82\xCD\x85\xCE\xB7\xCC\x93\xCD" "\x85\xCE\xB7\xCC\x94\xCD\x85\xCE\xB7\xCC\x93\xCC\x80\xCD\x85\xCE\xB7\xCC\x94\xCC\x80\xCD\x85\xCE\xB7" "\xCC\x93\xCC\x81\xCD\x85\xCE\xB7\xCC\x94\xCC\x81\xCD\x85\xCE\xB7\xCC\x93\xCD\x82\xCD\x85\xCE\xB7\xCC" "\x94\xCD\x82\xCD\x85\xCE\x97\xCC\x93\xCD\x85\xCE\x97\xCC\x94\xCD\x85\xCE\x97\xCC\x93\xCC\x80\xCD\x85" "\xCE\x97\xCC\x94\xCC\x80\xCD\x85\xCE\x97\xCC\x93\xCC\x81\xCD\x85\xCE\x97\xCC\x94\xCC\x81\xCD\x85\xCE" "\x97\xCC\x93\xCD\x82\xCD\x85\xCE\x97\xCC\x94\xCD\x82\xCD\x85\xCF\x89\xCC\x93\xCD\x85\xCF\x89\xCC\x94" "\xCD\x85\xCF\x89\xCC\x93\xCC\x80\xCD\x85\xCF\x89\xCC\x94\xCC\x80\xCD\x85\xCF\x89\xCC\x93\xCC\x81\xCD" "\x85\xCF\x89\xCC\x94\xCC\x81\xCD\x85\xCF\x89\xCC\x93\xCD\x82\xCD\x85\xCF\x89\xCC\x94\xCD\x82\xCD\x85" "\xCE\xA9\xCC\x93\xCD\x85\xCE\xA9\xCC\x94\xCD\x85\xCE\xA9\xCC\x93\xCC\x80\xCD\x85\xCE\xA9\xCC\x94\xCC" "\x80\xCD\x85\xCE\xA9\xCC\x93\xCC\x81\xCD\x85\xCE\xA9\xCC\x94\xCC\x81\xCD\x85\xCE\xA9\xCC\x93\xCD\x82" "\xCD\x85\xCE\xA9\xCC\x94\xCD\x82\xCD\x85\xCE\xB1\xCC\x86\xCE\xB1\xCC\x84\xCE\xB1\xCC\x80\xCD\x85\xCE" "\xB1\xCD\x85\xCE\xB1\xCC\x81\xCD\x85\xCE\xB1\xCD\x82\xCE\xB1\xCD\x82\xCD\x85\xCE\x91\xCC\x86\xCE\x91" "\xCC\x84\xCE\x91\xCC\x80\xCE\x91\xCD\x85\xC2\xA8\xCD\x82\xCE\xB7\xCC\x80\xCD\x85\xCE\xB7\xCD\x85\xCE" "\xB7\xCC\x81\xCD\x85\xCE\xB7\xCD\x82\xCE\xB7\xCD\x82\xCD\x85\xCE\x95\xCC\x80\xCE\x97\xCC\x80\xCE\x97" "\xCD\x85\xE1\xBE\xBF\xCC\x80\xE1\xBE\xBF\xCC\x81\xE1\xBE\xBF\xCD\x82\xCE\xB9\xCC\x86\xCE\xB9\xCC\x84" "\xCE\xB9\xCC\x88\xCC\x80\xCE\xB9\xCD\x82\xCE\xB9\xCC\x88\xCD\x82\xCE\x99\xCC\x86\xCE\x99\xCC\x84\xCE" "\x99\xCC\x80\xE1\xBF\xBE\xCC\x80\xE1\xBF\xBE\xCC\x81\xE1\xBF\xBE\xCD\x82\xCF\x85\xCC\x86\xCF\x85\xCC" "\x84\xCF\x85\xCC\x88\xCC\x80\xCF\x81\xCC\x93\xCF\x81\xCC\x94\xCF\x85\xCD\x82\xCF\x85\xCC\x88\xCD\x82" "\xCE\xA5\xCC\x86\xCE\xA5\xCC\x84\xCE\xA5\xCC\x80\xCE\xA1\xCC\x94\xC2\xA8\xCC\x80\x60\xCF\x89\xCC\x80" "\xCD\x85\xCF\x89\xCD\x85\xCF\x89\xCC\x81\xCD\x85\xCF\x89\xCD\x82\xCF\x89\xCD\x82\xCD\x85\xCE\x9F\xCC" "\x80\xCE\xA9\xCC\x80\xCE\xA9\xCD\x85\xC2\xB4\xE2\x80\x82\xE2\x80\x83\xE2\x86\x90\xCC\xB8\xE2\x86\x92" "\xCC\xB8\xE2\x86\x94\xCC\xB8\xE2\x87\x90\xCC\xB8\xE2\x87\x94\xCC\xB8\xE2\x87\x92\xCC\xB8\xE2\x88\x83" "\xCC\xB8\xE2\x88\x88\xCC\xB8\xE2\x88\x8B\xCC\xB8\xE2\x88\xA3\xCC\xB8\xE2\x88\xA5\xCC\xB8\xE2\x88\xBC" "\xCC\xB8\xE2\x89\x83\xCC\xB8\xE2\x89\x85\xCC\xB8\xE2\x89\x88\xCC\xB8\x3D\xCC\xB8\xE2\x89\xA1\xCC\xB8" "\xE2\x89\x8D\xCC\xB8\x3C\xCC\xB8\x3E\xCC\xB8\xE2\x89\xA4\xCC\xB8\xE2\x89\xA5\xCC\xB8\xE2\x89\xB2\xCC" "\xB8\xE2\x89\xB3\xCC\xB8\xE2\x89\xB6\xCC\xB8\xE2\x89\xB7\xCC\xB8\xE2\x89\xBA\xCC\xB8\xE2\x89\xBB\xCC" "\xB8\xE2\x8A\x82\xCC\xB8\xE2\x8A\x83\xCC\xB8\xE2\x8A\x86\xCC\xB8\xE2\x8A\x87\xCC\xB8\xE2\x8A\xA2\xCC" "\xB8\xE2\x8A\xA8\xCC\xB8\xE2\x8A\xA9\xCC\xB8\xE2\x8A\xAB\xCC\xB8\xE2\x89\xBC\xCC\xB8\xE2\x89\xBD\xCC" "\xB8\xE2\x8A\x91\xCC\xB8\xE2\x8A\x92\xCC\xB8\xE2\x8A\xB2\xCC\xB8\xE2\x8A\xB3\xCC\xB8\xE2\x8A\xB4\xCC" "\xB8\xE2\x8A\xB5\xCC\xB8\xE3\x80\x88\xE3\x80\x89\xE2\xAB\x9D\xCC\xB8\xE3\x81\x8B\xE3\x82\x99\xE3\x81" "\x8D\xE3\x82\x99\xE3\x81\x8F\xE3\x82\x99\xE3\x81\x91\xE3\x82\x99\xE3\x81\x93\xE3\x82\x99\xE3\x81\x95" "\xE3\x82\x99\xE3\x81\x97\xE3\x82\x99\xE3\x81\x99\xE3\x82\x99\xE3\x81\x9B\xE3\x82\x99\xE3\x81\x9D\xE3" "\x82\x99\xE3\x81\x9F\xE3\x82\x99\xE3\x81\xA1\xE3\x82\x99\xE3\x81\xA4\xE3\x82\x99\xE3\x81\xA6\xE3\x82" "\x99\xE3\x81\xA8\xE3\x82\x99\xE3\x81\xAF\xE3\x82\x99\xE3\x81\xAF\xE3\x82\x9A\xE3\x81\xB2\xE3\x82\x99" "\xE3\x81\xB2\xE3\x82\x9A\xE3\x81\xB5\xE3\x82\x99\xE3\x81\xB5\xE3\x82\x9A\xE3\x81\xB8\xE3\x82\x99\xE3" "\x81\xB8\xE3\x82\x9A\xE3\x81\xBB\xE3\x82\x99\xE3\x81\xBB\xE3\x82\x9A\xE3\x81\x86\xE3\x82\x99\xE3\x82" "\x9D\xE3\x82\x99\xE3\x82\xAB\xE3\x82\x99\xE3\x82\xAD\xE3\x82\x99\xE3\x82\xAF\xE3\x82\x99\xE3\x82\xB1" "\xE3\x82\x99\xE3\x82\xB3\xE3\x82\x99\xE3\x82\xB5\xE3\x82\x99\xE3\x82\xB7\xE3\x82\x99\xE3\x82\xB9\xE3" "\x82\x99\xE3\x82\xBB\xE3\x82\x99\xE3\x82\xBD\xE3\x82\x99\xE3\x82\xBF\xE3\x82\x99\xE3\x83\x81\xE3\x82" "\x99\xE3\x83\x84\xE3\x82\x99\xE3\x83\x86\xE3\x82\x99\xE3\x83\x88\xE3\x82\x99\xE3\x83\x8F\xE3\x82\x99" "\xE3\x83\x8F\xE3\x82\x9A\xE3\x83\x92\xE3\x82\x99\xE3\x83\x92\xE3\x82\x9A\xE3\x83\x95\xE3\x82\x99\xE3" "\x83\x95\xE3\x82\x9A\xE3\x83\x98\xE3\x82\x99\xE3\x83\x98\xE3\x82\x9A\xE3\x83\x9B\xE3\x82\x99\xE3\x83" "\x9B\xE3\x82\x9A\xE3\x82\xA6\xE3\x82\x99\xE3\x83\xAF\xE3\x82\x99\xE3\x83\xB0\xE3\x82\x99\xE3\x83\xB1" "\xE3\x82\x99\xE3\x83\xB2\xE3\x82\x99\xE3\x83\xBD\xE3\x82\x99\xE8\xB1\x88\xE6\x9B\xB4\xE8\xBB\x8A\xE8" "\xB3\x88\xE6\xBB\x91\xE4\xB8\xB2\xE5\x8F\xA5\xE9\xBE\x9C\xE5\xA5\x91\xE9\x87\x91\xE5\x96\x87\xE5\xA5" "\x88\xE6\x87\xB6\xE7\x99\xA9\xE7\xBE\x85\xE8\x98\xBF\xE8\x9E\xBA\xE8\xA3\xB8\xE9\x82\x8F\xE6\xA8\x82" "\xE6\xB4\x9B\xE7\x83\x99\xE7\x8F\x9E\xE8\x90\xBD\xE9\x85\xAA\xE9\xA7\xB1\xE4\xBA\x82\xE5\x8D\xB5\xE6" "\xAC\x84\xE7\x88\x9B\xE8\x98\xAD\xE9\xB8\x9E\xE5\xB5\x90\xE6\xBF\xAB\xE8\x97\x8D\xE8\xA5\xA4\xE6\x8B" "\x89\xE8\x87\x98\xE8\xA0\x9F\xE5\xBB\x8A\xE6\x9C\x97\xE6\xB5\xAA\xE7\x8B\xBC\xE9\x83\x8E\xE4\xBE\x86" "\xE5\x86\xB7\xE5\x8B\x9E\xE6\x93\x84\xE6\xAB\x93\xE7\x88\x90\xE7\x9B\xA7\xE8\x80\x81\xE8\x98\x86\xE8" "\x99\x9C\xE8\xB7\xAF\xE9\x9C\xB2\xE9\xAD\xAF\xE9\xB7\xBA\xE7\xA2\x8C\xE7\xA5\xBF\xE7\xB6\xA0\xE8\x8F" "\x89\xE9\x8C\x84\xE9\xB9\xBF\xE8\xAB\x96\xE5\xA3\x9F\xE5\xBC\x84\xE7\xB1\xA0\xE8\x81\xBE\xE7\x89\xA2" "\xE7\xA3\x8A\xE8\xB3\x82\xE9\x9B\xB7\xE5\xA3\x98\xE5\xB1\xA2\xE6\xA8\x93\xE6\xB7\x9A\xE6\xBC\x8F\xE7" "\xB4\xAF\xE7\xB8\xB7\xE9\x99\x8B\xE5\x8B\x92\xE8\x82\x8B\xE5\x87\x9C\xE5\x87\x8C\xE7\xA8\x9C\xE7\xB6" "\xBE\xE8\x8F\xB1\xE9\x99\xB5\xE8\xAE\x80\xE6\x8B\x8F\xE8\xAB\xBE\xE4\xB8\xB9\xE5\xAF\xA7\xE6\x80\x92" "\xE7\x8E\x87\xE7\x95\xB0\xE5\x8C\x97\xE7\xA3\xBB\xE4\xBE\xBF\xE5\xBE\xA9\xE4\xB8\x8D\xE6\xB3\x8C\xE6" "\x95\xB8\xE7\xB4\xA2\xE5\x8F\x83\xE5\xA1\x9E\xE7\x9C\x81\xE8\x91\x89\xE8\xAA\xAA\xE6\xAE\xBA\xE8\xBE" "\xB0\xE6\xB2\x88\xE6\x8B\xBE\xE8\x8B\xA5\xE6\x8E\xA0\xE7\x95\xA5\xE4\xBA\xAE\xE5\x85\xA9\xE5\x87\x89" "\xE6\xA2\x81\xE7\xB3\xA7\xE8\x89\xAF\xE8\xAB\x92\xE9\x87\x8F\xE5\x8B\xB5\xE5\x91\x82\xE5\xA5\xB3\xE5" "\xBB\xAC\xE6\x97\x85\xE6\xBF\xBE\xE7\xA4\xAA\xE9\x96\xAD\xE9\xA9\xAA\xE9\xBA\x97\xE9\xBB\x8E\xE5\x8A" "\x9B\xE6\x9B\x86\xE6\xAD\xB7\xE8\xBD\xA2\xE5\xB9\xB4\xE6\x86\x90\xE6\x88\x80\xE6\x92\x9A\xE6\xBC\xA3" "\xE7\x85\x89\xE7\x92\x89\xE7\xA7\x8A\xE7\xB7\xB4\xE8\x81\xAF\xE8\xBC\xA6\xE8\x93\xAE\xE9\x80\xA3\xE9" "\x8D\x8A\xE5\x88\x97\xE5\x8A\xA3\xE5\x92\xBD\xE7\x83\x88\xE8\xA3\x82\xE5\xBB\x89\xE5\xBF\xB5\xE6\x8D" "\xBB\xE6\xAE\xAE\xE7\xB0\xBE\xE7\x8D\xB5\xE4\xBB\xA4\xE5\x9B\xB9\xE5\xB6\xBA\xE6\x80\x9C\xE7\x8E\xB2" "\xE7\x91\xA9\xE7\xBE\x9A\xE8\x81\x86\xE9\x88\xB4\xE9\x9B\xB6\xE9\x9D\x88\xE9\xA0\x98\xE4\xBE\x8B\xE7" "\xA6\xAE\xE9\x86\xB4\xE9\x9A\xB8\xE6\x83\xA1\xE4\xBA\x86\xE5\x83\x9A\xE5\xAF\xAE\xE5\xB0\xBF\xE6\x96" "\x99\xE7\x87\x8E\xE7\x99\x82\xE8\x93\xBC\xE9\x81\xBC\xE9\xBE\x8D\xE6\x9A\x88\xE9\x98\xAE\xE5\x8A\x89" "\xE6\x9D\xBB\xE6\x9F\xB3\xE6\xB5\x81\xE6\xBA\x9C\xE7\x90\x89\xE7\x95\x99\xE7\xA1\xAB\xE7\xB4\x90\xE9" "\xA1\x9E\xE5\x85\xAD\xE6\x88\xAE\xE9\x99\xB8\xE5\x80\xAB\xE5\xB4\x99\xE6\xB7\xAA\xE8\xBC\xAA\xE5\xBE" "\x8B\xE6\x85\x84\xE6\xA0\x97\xE9\x9A\x86\xE5\x88\xA9\xE5\x90\x8F\xE5\xB1\xA5\xE6\x98\x93\xE6\x9D\x8E" "\xE6\xA2\xA8\xE6\xB3\xA5\xE7\x90\x86\xE7\x97\xA2\xE7\xBD\xB9\xE8\xA3\x8F\xE8\xA3\xA1\xE9\x87\x8C\xE9" "\x9B\xA2\xE5\x8C\xBF\xE6\xBA\xBA\xE5\x90\x9D\xE7\x87\x90\xE7\x92\x98\xE8\x97\xBA\xE9\x9A\xA3\xE9\xB1" "\x97\xE9\xBA\x9F\xE6\x9E\x97\xE6\xB7\x8B\xE8\x87\xA8\xE7\xAB\x8B\xE7\xAC\xA0\xE7\xB2\x92\xE7\x8B\x80" "\xE7\x82\x99\xE8\xAD\x98\xE4\xBB\x80\xE8\x8C\xB6\xE5\x88\xBA\xE5\x88\x87\xE5\xBA\xA6\xE6\x8B\x93\xE7" "\xB3\x96\xE5\xAE\x85\xE6\xB4\x9E\xE6\x9A\xB4\xE8\xBC\xBB\xE8\xA1\x8C\xE9\x99\x8D\xE8\xA6\x8B\xE5\xBB" "\x93\xE5\x85\x80\xE5\x97\x80\xE5\xA1\x9A\xE6\x99\xB4\xE5\x87\x9E\xE7\x8C\xAA\xE7\x9B\x8A\xE7\xA4\xBC" "\xE7\xA5\x9E\xE7\xA5\xA5\xE7\xA6\x8F\xE9\x9D\x96\xE7\xB2\xBE\xE7\xBE\xBD\xE8\x98\x92\xE8\xAB\xB8\xE9" "\x80\xB8\xE9\x83\xBD\xE9\xA3\xAF\xE9\xA3\xBC\xE9\xA4\xA8\xE9\xB6\xB4\xE9\x83\x9E\xE9\x9A\xB7\xE4\xBE" "\xAE\xE5\x83\xA7\xE5\x85\x8D\xE5\x8B\x89\xE5\x8B\xA4\xE5\x8D\x91\xE5\x96\x9D\xE5\x98\x86\xE5\x99\xA8" "\xE5\xA1\x80\xE5\xA2\xA8\xE5\xB1\xA4\xE5\xB1\xAE\xE6\x82\x94\xE6\x85\xA8\xE6\x86\x8E\xE6\x87\xB2\xE6" "\x95\x8F\xE6\x97\xA2\xE6\x9A\x91\xE6\xA2\x85\xE6\xB5\xB7\xE6\xB8\x9A\xE6\xBC\xA2\xE7\x85\xAE\xE7\x88" "\xAB\xE7\x90\xA2\xE7\xA2\x91\xE7\xA4\xBE\xE7\xA5\x89\xE7\xA5\x88\xE7\xA5\x90\xE7\xA5\x96\xE7\xA5\x9D" "\xE7\xA6\x8D\xE7\xA6\x8E\xE7\xA9\x80\xE7\xAA\x81\xE7\xAF\x80\xE7\xB8\x89\xE7\xB9\x81\xE7\xBD\xB2\xE8" "\x80\x85\xE8\x87\xAD\xE8\x89\xB9\xE8\x91\x97\xE8\xA4\x90\xE8\xA6\x96\xE8\xAC\x81\xE8\xAC\xB9\xE8\xB3" "\x93\xE8\xB4\x88\xE8\xBE\xB6\xE9\x9B\xA3\xE9\x9F\xBF\xE9\xA0\xBB\xE6\x81\xB5\xF0\xA4\x8B\xAE\xE8\x88" "\x98\xE4\xB8\xA6\xE5\x86\xB5\xE5\x85\xA8\xE4\xBE\x80\xE5\x85\x85\xE5\x86\x80\xE5\x8B\x87\xE5\x8B\xBA" "\xE5\x95\x95\xE5\x96\x99\xE5\x97\xA2\xE5\xA2\xB3\xE5\xA5\x84\xE5\xA5\x94\xE5\xA9\xA2\xE5\xAC\xA8\xE5" "\xBB\x92\xE5\xBB\x99\xE5\xBD\xA9\xE5\xBE\xAD\xE6\x83\x98\xE6\x85\x8E\xE6\x84\x88\xE6\x85\xA0\xE6\x88" "\xB4\xE6\x8F\x84\xE6\x90\x9C\xE6\x91\x92\xE6\x95\x96\xE6\x9C\x9B\xE6\x9D\x96\xE6\xAD\xB9\xE6\xBB\x9B" "\xE6\xBB\x8B\xE7\x80\x9E\xE7\x9E\xA7\xE7\x88\xB5\xE7\x8A\xAF\xE7\x91\xB1\xE7\x94\x86\xE7\x94\xBB\xE7" "\x98\x9D\xE7\x98\x9F\xE7\x9B\x9B\xE7\x9B\xB4\xE7\x9D\x8A\xE7\x9D\x80\xE7\xA3\x8C\xE7\xAA\xB1\xE7\xB1" "\xBB\xE7\xB5\x9B\xE7\xBC\xBE\xE8\x8D\x92\xE8\x8F\xAF\xE8\x9D\xB9\xE8\xA5\x81\xE8\xA6\x86\xE8\xAA\xBF" "\xE8\xAB\x8B\xE8\xAB\xAD\xE8\xAE\x8A\xE8\xBC\xB8\xE9\x81\xB2\xE9\x86\x99\xE9\x89\xB6\xE9\x99\xBC\xE9" "\x9F\x9B\xE9\xA0\x8B\xE9\xAC\x92\xF0\xA2\xA1\x8A\xF0\xA2\xA1\x84\xF0\xA3\x8F\x95\xE3\xAE\x9D\xE4\x80" "\x98\xE4\x80\xB9\xF0\xA5\x89\x89\xF0\xA5\xB3\x90\xF0\xA7\xBB\x93\xE9\xBD\x83\xE9\xBE\x8E\xD7\x99\xD6" "\xB4\xD7\xB2\xD6\xB7\xD7\xA9\xD7\x81\xD7\xA9\xD7\x82\xD7\xA9\xD6\xBC\xD7\x81\xD7\xA9\xD6\xBC\xD7\x82" "\xD7\x90\xD6\xB7\xD7\x90\xD6\xB8\xD7\x90\xD6\xBC\xD7\x91\xD6\xBC\xD7\x92\xD6\xBC\xD7\x93\xD6\xBC\xD7" "\x94\xD6\xBC\xD7\x95\xD6\xBC\xD7\x96\xD6\xBC\xD7\x98\xD6\xBC\xD7\x99\xD6\xBC\xD7\x9A\xD6\xBC\xD7\x9B" "\xD6\xBC\xD7\x9C\xD6\xBC\xD7\x9E\xD6\xBC\xD7\xA0\xD6\xBC\xD7\xA1\xD6\xBC\xD7\xA3\xD6\xBC\xD7\xA4\xD6" "\xBC\xD7\xA6\xD6\xBC\xD7\xA7\xD6\xBC\xD7\xA8\xD6\xBC\xD7\xAA\xD6\xBC\xD7\x95\xD6\xB9\xD7\x91\xD6\xBF" "\xD7\x9B\xD6\xBF\xD7\xA4\xD6\xBF\xF0\x91\x82\x99\xF0\x91\x82\xBA\xF0\x91\x82\x9B\xF0\x91\x82\xBA\xF0" "\x91\x82\xA5\xF0\x91\x82\xBA\xF0\x91\x84\xB1\xF0\x91\x84\xA7\xF0\x91\x84\xB2\xF0\x91\x84\xA7\xF0\x91" "\x8D\x87\xF0\x91\x8C\xBE\xF0\x91\x8D\x87\xF0\x91\x8D\x97\xF0\x91\x92\xB9\xF0\x91\x92\xBA\xF0\x91\x92" "\xB9\xF0\x91\x92\xB0\xF0\x91\x92\xB9\xF0\x91\x92\xBD\xF0\x91\x96\xB8\xF0\x91\x96\xAF\xF0\x91\x96\xB9" "\xF0\x91\x96\xAF\xF0\x9D\x85\x97\xF0\x9D\x85\xA5\xF0\x9D\x85\x98\xF0\x9D\x85\xA5\xF0\x9D\x85\x98\xF0" "\x9D\x85\xA5\xF0\x9D\x85\xAE\xF0\x9D\x85\x98\xF0\x9D\x85\xA5\xF0\x9D\x85\xAF\xF0\x9D\x85\x98\xF0\x9D" "\x85\xA5\xF0\x9D\x85\xB0\xF0\x9D\x85\x98\xF0\x9D\x85\xA5\xF0\x9D\x85\xB1\xF0\x9D\x85\x98\xF0\x9D\x85" "\xA5\xF0\x9D\x85\xB2\xF0\x9D\x86\xB9\xF0\x9D\x85\xA5\xF0\x9D\x86\xBA\xF0\x9D\x85\xA5\xF0\x9D\x86\xB9" "\xF0\x9D\x85\xA5\xF0\x9D\x85\xAE\xF0\x9D\x86\xBA\xF0\x9D\x85\xA5\xF0\x9D\x85\xAE\xF0\x9D\x86\xB9\xF0" "\x9D\x85\xA5\xF0\x9D\x85\xAF\xF0\x9D\x86\xBA\xF0\x9D\x85\xA5\xF0\x9D\x85\xAF\xE4\xB8\xBD\xE4\xB8\xB8" "\xE4\xB9\x81\xF0\xA0\x84\xA2\xE4\xBD\xA0\xE4\xBE\xBB\xE5\x80\x82\xE5\x81\xBA\xE5\x82\x99\xE5\x83\x8F" "\xE3\x92\x9E\xF0\xA0\x98\xBA\xE5\x85\x94\xE5\x85\xA4\xE5\x85\xB7\xF0\xA0\x94\x9C\xE3\x92\xB9\xE5\x85" "\xA7\xE5\x86\x8D\xF0\xA0\x95\x8B\xE5\x86\x97\xE5\x86\xA4\xE4\xBB\x8C\xE5\x86\xAC\xF0\xA9\x87\x9F\xE5" "\x87\xB5\xE5\x88\x83\xE3\x93\x9F\xE5\x88\xBB\xE5\x89\x86\xE5\x89\xB2\xE5\x89\xB7\xE3\x94\x95\xE5\x8C" "\x85\xE5\x8C\x86\xE5\x8D\x89\xE5\x8D\x9A\xE5\x8D\xB3\xE5\x8D\xBD\xE5\x8D\xBF\xF0\xA0\xA8\xAC\xE7\x81" "\xB0\xE5\x8F\x8A\xE5\x8F\x9F\xF0\xA0\xAD\xA3\xE5\x8F\xAB\xE5\x8F\xB1\xE5\x90\x86\xE5\x92\x9E\xE5\x90" "\xB8\xE5\x91\x88\xE5\x91\xA8\xE5\x92\xA2\xE5\x93\xB6\xE5\x94\x90\xE5\x95\x93\xE5\x95\xA3\xE5\x96\x84" "\xE5\x96\xAB\xE5\x96\xB3\xE5\x97\x82\xE5\x9C\x96\xE5\x9C\x97\xE5\x99\x91\xE5\x99\xB4\xE5\xA3\xAE\xE5" "\x9F\x8E\xE5\x9F\xB4\xE5\xA0\x8D\xE5\x9E\x8B\xE5\xA0\xB2\xE5\xA0\xB1\xE5\xA2\xAC\xF0\xA1\x93\xA4\xE5" "\xA3\xB2\xE5\xA3\xB7\xE5\xA4\x86\xE5\xA4\x9A\xE5\xA4\xA2\xE5\xA5\xA2\xF0\xA1\x9A\xA8\xF0\xA1\x9B\xAA" "\xE5\xA7\xAC\xE5\xA8\x9B\xE5\xA8\xA7\xE5\xA7\x98\xE5\xA9\xA6\xE3\x9B\xAE\xE3\x9B\xBC\xE5\xAC\x88\xE5" "\xAC\xBE\xF0\xA1\xA7\x88\xE5\xAF\x83\xE5\xAF\x98\xE5\xAF\xB3\xF0\xA1\xAC\x98\xE5\xAF\xBF\xE5\xB0\x86" "\xE5\xBD\x93\xE5\xB0\xA2\xE3\x9E\x81\xE5\xB1\xA0\xE5\xB3\x80\xE5\xB2\x8D\xF0\xA1\xB7\xA4\xE5\xB5\x83" "\xF0\xA1\xB7\xA6\xE5\xB5\xAE\xE5\xB5\xAB\xE5\xB5\xBC\xE5\xB7\xA1\xE5\xB7\xA2\xE3\xA0\xAF\xE5\xB7\xBD" "\xE5\xB8\xA8\xE5\xB8\xBD\xE5\xB9\xA9\xE3\xA1\xA2\xF0\xA2\x86\x83\xE3\xA1\xBC\xE5\xBA\xB0\xE5\xBA\xB3" "\xE5\xBA\xB6\xF0\xAA\x8E\x92\xE5\xBB\xBE\xF0\xA2\x8C\xB1\xE8\x88\x81\xE5\xBC\xA2\xE3\xA3\x87\xF0\xA3" "\x8A\xB8\xF0\xA6\x87\x9A\xE5\xBD\xA2\xE5\xBD\xAB\xE3\xA3\xA3\xE5\xBE\x9A\xE5\xBF\x8D\xE5\xBF\x97\xE5" "\xBF\xB9\xE6\x82\x81\xE3\xA4\xBA\xE3\xA4\x9C\xF0\xA2\x9B\x94\xE6\x83\x87\xE6\x85\x88\xE6\x85\x8C\xE6" "\x85\xBA\xE6\x86\xB2\xE6\x86\xA4\xE6\x86\xAF\xE6\x87\x9E\xE6\x88\x90\xE6\x88\x9B\xE6\x89\x9D\xE6\x8A" "\xB1\xE6\x8B\x94\xE6\x8D\x90\xF0\xA2\xAC\x8C\xE6\x8C\xBD\xE6\x8B\xBC\xE6\x8D\xA8\xE6\x8E\x83\xE6\x8F" "\xA4\xF0\xA2\xAF\xB1\xE6\x90\xA2\xE6\x8F\x85\xE6\x8E\xA9\xE3\xA8\xAE\xE6\x91\xA9\xE6\x91\xBE\xE6\x92" "\x9D\xE6\x91\xB7\xE3\xA9\xAC\xE6\x95\xAC\xF0\xA3\x80\x8A\xE6\x97\xA3\xE6\x9B\xB8\xE6\x99\x89\xE3\xAC" "\x99\xE3\xAC\x88\xE3\xAB\xA4\xE5\x86\x92\xE5\x86\x95\xE6\x9C\x80\xE6\x9A\x9C\xE8\x82\xAD\xE4\x8F\x99" "\xE6\x9C\xA1\xE6\x9D\x9E\xE6\x9D\x93\xF0\xA3\x8F\x83\xE3\xAD\x89\xE6\x9F\xBA\xE6\x9E\x85\xE6\xA1\x92" "\xF0\xA3\x91\xAD\xE6\xA2\x8E\xE6\xA0\x9F\xE6\xA4\x94\xE6\xA5\x82\xE6\xA6\xA3\xE6\xA7\xAA\xE6\xAA\xA8" "\xF0\xA3\x9A\xA3\xE6\xAB\x9B\xE3\xB0\x98\xE6\xAC\xA1\xF0\xA3\xA2\xA7\xE6\xAD\x94\xE3\xB1\x8E\xE6\xAD" "\xB2\xE6\xAE\x9F\xE6\xAE\xBB\xF0\xA3\xAA\x8D\xF0\xA1\xB4\x8B\xF0\xA3\xAB\xBA\xE6\xB1\x8E\xF0\xA3\xB2" "\xBC\xE6\xB2\xBF\xE6\xB3\x8D\xE6\xB1\xA7\xE6\xB4\x96\xE6\xB4\xBE\xE6\xB5\xA9\xE6\xB5\xB8\xE6\xB6\x85" "\xF0\xA3\xB4\x9E\xE6\xB4\xB4\xE6\xB8\xAF\xE6\xB9\xAE\xE3\xB4\xB3\xE6\xBB\x87\xF0\xA3\xBB\x91\xE6\xB7" "\xB9\xE6\xBD\xAE\xF0\xA3\xBD\x9E\xF0\xA3\xBE\x8E\xE6\xBF\x86\xE7\x80\xB9\xE7\x80\x9B\xE3\xB6\x96\xE7" "\x81\x8A\xE7\x81\xBD\xE7\x81\xB7\xE7\x82\xAD\xF0\xA0\x94\xA5\xE7\x85\x85\xF0\xA4\x89\xA3\xE7\x86\x9C" "\xF0\xA4\x8E\xAB\xE7\x88\xA8\xE7\x89\x90\xF0\xA4\x98\x88\xE7\x8A\x80\xE7\x8A\x95\xF0\xA4\x9C\xB5\xF0" "\xA4\xA0\x94\xE7\x8D\xBA\xE7\x8E\x8B\xE3\xBA\xAC\xE7\x8E\xA5\xE3\xBA\xB8\xE7\x91\x87\xE7\x91\x9C\xE7" "\x92\x85\xE7\x93\x8A\xE3\xBC\x9B\xE7\x94\xA4\xF0\xA4\xB0\xB6\xE7\x94\xBE\xF0\xA4\xB2\x92\xF0\xA2\x86" "\x9F\xE7\x98\x90\xF0\xA4\xBE\xA1\xF0\xA4\xBE\xB8\xF0\xA5\x81\x84\xE3\xBF\xBC\xE4\x80\x88\xF0\xA5\x83" "\xB3\xF0\xA5\x83\xB2\xF0\xA5\x84\x99\xF0\xA5\x84\xB3\xE7\x9C\x9E\xE7\x9C\x9F\xE7\x9E\x8B\xE4\x81\x86" "\xE4\x82\x96\xF0\xA5\x90\x9D\xE7\xA1\x8E\xE4\x83\xA3\xF0\xA5\x98\xA6\xF0\xA5\x9A\x9A\xF0\xA5\x9B\x85" "\xE7\xA7\xAB\xE4\x84\xAF\xE7\xA9\x8A\xE7\xA9\x8F\xF0\xA5\xA5\xBC\xF0\xA5\xAA\xA7\xE7\xAB\xAE\xE4\x88" "\x82\xF0\xA5\xAE\xAB\xE7\xAF\x86\xE7\xAF\x89\xE4\x88\xA7\xF0\xA5\xB2\x80\xE7\xB3\x92\xE4\x8A\xA0\xE7" "\xB3\xA8\xE7\xB3\xA3\xE7\xB4\x80\xF0\xA5\xBE\x86\xE7\xB5\xA3\xE4\x8C\x81\xE7\xB7\x87\xE7\xB8\x82\xE7" "\xB9\x85\xE4\x8C\xB4\xF0\xA6\x88\xA8\xF0\xA6\x89\x87\xE4\x8D\x99\xF0\xA6\x8B\x99\xE7\xBD\xBA\xF0\xA6" "\x8C\xBE\xE7\xBE\x95\xE7\xBF\xBA\xF0\xA6\x93\x9A\xF0\xA6\x94\xA3\xE8\x81\xA0\xF0\xA6\x96\xA8\xE8\x81" "\xB0\xF0\xA3\x8D\x9F\xE4\x8F\x95\xE8\x82\xB2\xE8\x84\x83\xE4\x90\x8B\xE8\x84\xBE\xE5\xAA\xB5\xF0\xA6" "\x9E\xA7\xF0\xA6\x9E\xB5\xF0\xA3\x8E\x93\xF0\xA3\x8E\x9C\xE8\x88\x84\xE8\xBE\x9E\xE4\x91\xAB\xE8\x8A" "\x91\xE8\x8A\x8B\xE8\x8A\x9D\xE5\x8A\xB3\xE8\x8A\xB1\xE8\x8A\xB3\xE8\x8A\xBD\xE8\x8B\xA6\xF0\xA6\xAC" "\xBC\xE8\x8C\x9D\xE8\x8D\xA3\xE8\x8E\xAD\xE8\x8C\xA3\xE8\x8E\xBD\xE8\x8F\xA7\xE8\x8D\x93\xE8\x8F\x8A" "\xE8\x8F\x8C\xE8\x8F\x9C\xF0\xA6\xB0\xB6\xF0\xA6\xB5\xAB\xF0\xA6\xB3\x95\xE4\x94\xAB\xE8\x93\xB1\xE8" "\x93\xB3\xE8\x94\x96\xF0\xA7\x8F\x8A\xE8\x95\xA4\xF0\xA6\xBC\xAC\xE4\x95\x9D\xE4\x95\xA1\xF0\xA6\xBE" "\xB1\xF0\xA7\x83\x92\xE4\x95\xAB\xE8\x99\x90\xE8\x99\xA7\xE8\x99\xA9\xE8\x9A\xA9\xE8\x9A\x88\xE8\x9C" "\x8E\xE8\x9B\xA2\xE8\x9C\xA8\xE8\x9D\xAB\xE8\x9E\x86\xE4\x97\x97\xE8\x9F\xA1\xE8\xA0\x81\xE4\x97\xB9" "\xE8\xA1\xA0\xE8\xA1\xA3\xF0\xA7\x99\xA7\xE8\xA3\x97\xE8\xA3\x9E\xE4\x98\xB5\xE8\xA3\xBA\xE3\x92\xBB" "\xF0\xA7\xA2\xAE\xF0\xA7\xA5\xA6\xE4\x9A\xBE\xE4\x9B\x87\xE8\xAA\xA0\xE8\xB1\x95\xF0\xA7\xB2\xA8\xE8" "\xB2\xAB\xE8\xB3\x81\xE8\xB4\x9B\xE8\xB5\xB7\xF0\xA7\xBC\xAF\xF0\xA0\xA0\x84\xE8\xB7\x8B\xE8\xB6\xBC" "\xE8\xB7\xB0\xF0\xA0\xA3\x9E\xE8\xBB\x94\xF0\xA8\x97\x92\xF0\xA8\x97\xAD\xE9\x82\x94\xE9\x83\xB1\xE9" "\x84\x91\xF0\xA8\x9C\xAE\xE9\x84\x9B\xE9\x88\xB8\xE9\x8B\x97\xE9\x8B\x98\xE9\x89\xBC\xE9\x8F\xB9\xE9" "\x90\x95\xF0\xA8\xAF\xBA\xE9\x96\x8B\xE4\xA6\x95\xE9\x96\xB7\xF0\xA8\xB5\xB7\xE4\xA7\xA6\xE9\x9B\x83" "\xE5\xB6\xB2\xE9\x9C\xA3\xF0\xA9\x85\x85\xF0\xA9\x88\x9A\xE4\xA9\xAE\xE4\xA9\xB6\xE9\x9F\xA0\xF0\xA9" "\x90\x8A\xE4\xAA\xB2\xF0\xA9\x92\x96\xE9\xA0\xA9\xF0\xA9\x96\xB6\xE9\xA3\xA2\xE4\xAC\xB3\xE9\xA4\xA9" "\xE9\xA6\xA7\xE9\xA7\x82\xE9\xA7\xBE\xE4\xAF\x8E\xF0\xA9\xAC\xB0\xE9\xB1\x80\xE9\xB3\xBD\xE4\xB3\x8E" "\xE4\xB3\xAD\xE9\xB5\xA7\xF0\xAA\x83\x8E\xE4\xB3\xB8\xF0\xAA\x84\x85\xF0\xAA\x88\x8E\xF0\xAA\x8A\x91" "\xE9\xBA\xBB\xE4\xB5\x96\xE9\xBB\xB9\xE9\xBB\xBE\xE9\xBC\x85\xE9\xBC\x8F\xE9\xBC\x96\xE9\xBC\xBB\xF0" "\xAA\x98\x80\x20\x20\xCC\x88\x20\xCC\x84\x32\x33\x20\xCC\x81\xCE\xBC\x20\xCC\xA7\x31\x31\xE2\x81\x84" "\x34\x31\xE2\x81\x84\x32\x33\xE2\x81\x84\x34\x49\x4A\x69\x6A\x4C\xC2\xB7\x6C\xC2\xB7\xCA\xBC\x6E\x44" "\x5A\xCC\x8C\x44\x7A\xCC\x8C\x64\x7A\xCC\x8C\x4C\x4A\x4C\x6A\x6C\x6A\x4E\x4A\x4E\x6A\x6E\x6A\xC9\xA6" "\xC9\xB9\xC9\xBB\xCA\x81\x20\xCC\x86\x20\xCC\x87\x20\xCC\x8A\x20\xCC\xA8\x20\xCC\x83\x20\xCC\x8B\xC9" "\xA3\xCA\x95\x20\xCD\x85\x20\xCC\x88\xCC\x81\xCE\xB2\xCE\xB8\xCF\x86\xCF\x80\xCE\xBA\xCF\x82\xCE\x98" "\xCE\xA3\xD5\xA5\xD6\x82\xD8\xA7\xD9\xB4\xD9\x88\xD9\xB4\xDB\x87\xD9\xB4\xD9\x8A\xD9\xB4\xE0\xB3\x86" "\xE0\xB3\x82\xE0\xB3\x95\xE0\xB7\x99\xE0\xB7\x8F\xE0\xB7\x8A\xE0\xB9\x8D\xE0\xB8\xB2\xE0\xBB\x8D\xE0" "\xBA\xB2\xE0\xBA\xAB\xE0\xBA\x99\xE0\xBA\xAB\xE0\xBA\xA1\xE0\xBC\x8B\xE0\xBE\xB2\xE0\xBD\xB1\xE0\xBE" "\x80\xE0\xBE\xB3\xE0\xBD\xB1\xE0\xBE\x80\xE1\x83\x9C\xC6\x8E\xC8\xA2\xC9\x90\xC9\x91\xE1\xB4\x82\xC9" "\x99\xC9\x9B\xC9\x9C\xC5\x8B\xC9\x94\xE1\xB4\x96\xE1\xB4\x97\xE1\xB4\x9D\xC9\xAF\xE1\xB4\xA5\xCE\xB3" "\xCE\xB4\xCF\x87\xD0\xBD\xC9\x92\xC9\x95\xC3\xB0\xC9\x9F\xC9\xA1\xC9\xA5\xC9\xA8\xC9\xA9\xC9\xAA\xE1" "\xB5\xBB\xCA\x9D\xC9\xAD\xE1\xB6\x85\xCA\x9F\xC9\xB1\xC9\xB0\xC9\xB2\xC9\xB3\xC9\xB4\xC9\xB5\xC9\xB8" "\xCA\x82\xCA\x83\xC6\xAB\xCA\x89\xCA\x8A\xE1\xB4\x9C\xCA\x8B\xCA\x8C\xCA\x90\xCA\x91\x61\xCA\xBE\xCE" "\xA5\xCC\x94\xCC\x80\xCE\xB1\xCD\x82\xCD\x85\x20\xCC\x93\x20\xCD\x82\x20\xCC\x88\xCD\x82\xCE\xB7\xCD" "\x82\xCD\x85\x20\xCC\x93\xCC\x80\x20\xCC\x93\xCC\x81\x20\xCC\x93\xCD\x82\x20\xCC\x94\xCC\x80\x20\xCC" "\x94\xCC\x81\x20\xCC\x94\xCD\x82\x20\xCC\x88\xCC\x80\xCF\x89\xCD\x82\xCD\x85\xE2\x80\x90\x20\xCC\xB3" "\x2E\x2E\x2E\xE2\x80\xB2\xE2\x80\xB2\xE2\x80\xB2\xE2\x80\xB2\xE2\x80\xB2\xE2\x80\xB5\xE2\x80\xB5\xE2" "\x80\xB5\xE2\x80\xB5\xE2\x80\xB5\x21\x21\x20\xCC\x85\x3F\x3F\x3F\x21\x21\x3F\x30\x35\x36\x37\x38\x39" "\x2B\xE2\x88\x92\x28\x29\x52\x73\x61\x2F\x63\x61\x2F\x73\xC2\xB0\x43\x63\x2F\x6F\x63\x2F\x75\xC6\x90" "\xC2\xB0\x46\xC4\xA7\x4E\x6F\x51\x53\x4D\x54\x45\x4C\x54\x4D\x46\x41\x58\xCE\x93\xCE\xA0\xE2\x88\x91" "\x31\xE2\x81\x84\x37\x31\xE2\x81\x84\x39\x31\xE2\x81\x84\x31\x30\x31\xE2\x81\x84\x33\x32\xE2\x81\x84" "\x33\x31\xE2\x81\x84\x35\x32\xE2\x81\x84\x35\x33\xE2\x81\x84\x35\x34\xE2\x81\x84\x35\x31\xE2\x81\x84" "\x36\x35\xE2\x81\x84\x36\x31\xE2\x81\x84\x38\x33\xE2\x81\x84\x38\x35\xE2\x81\x84\x38\x37\xE2\x81\x84" "\x38\x49\x49\x49\x49\x49\x49\x56\x56\x49\x56\x49\x49\x56\x49\x49\x49\x49\x58\x58\x49\x58\x49\x49\x69" "\x69\x69\x69\x69\x69\x76\x76\x69\x76\x69\x69\x76\x69\x69\x69\x69\x78\x78\x69\x78\x69\x69\x30\xE2\x81" "\x84\x33\xE2\x88\xAB\xE2\x88\xAB\xE2\x88\xAB\xE2\x88\xAB\xE2\x88\xAB\xE2\x88\xAE\xE2\x88\xAE\xE2\x88" "\xAE\xE2\x88\xAE\xE2\x88\xAE\x31\x32\x31\x33\x31\x34\x31\x35\x31\x36\x31\x37\x31\x38\x31\x39\x32\x30" "\x28\x31\x29\x28\x32\x29\x28\x33\x29\x28\x34\x29\x28\x35\x29\x28\x36\x29\x28\x37\x29\x28\x38\x29\x28" "\x39\x29\x28\x31\x30\x29\x28\x31\x31\x29\x28\x31\x32\x29\x28\x31\x33\x29\x28\x31\x34\x29\x28\x31\x35" "\x29\x28\x31\x36\x29\x28\x31\x37\x29\x28\x31\x38\x29\x28\x31\x39\x29\x28\x32\x30\x29\x31\x2E\x32\x2E" "\x33\x2E\x34\x2E\x35\x2E\x36\x2E\x37\x2E\x38\x2E\x39\x2E\x31\x30\x2E\x31\x31\x2E\x31\x32\x2E\x31\x33" "\x2E\x31\x34\x2E\x31\x35\x2E\x31\x36\x2E\x31\x37\x2E\x31\x38\x2E\x31\x39\x2E\x32\x30\x2E\x28\x61\x29" "\x28\x62\x29\x28\x63\x29\x28\x64\x29\x28\x65\x29\x28\x66\x29\x28\x67\x29\x28\x68\x29\x28\x69\x29\x28" "\x6A\x29\x28\x6B\x29\x28\x6C\x29\x28\x6D\x29\x28\x6E\x29\x28\x6F\x29\x28\x70\x29\x28\x71\x29\x28\x72" "\x29\x28\x73\x29\x28\x74\x29\x28\x75\x29\x28\x76\x29\x28\x77\x29\x28\x78\x29\x28\x79\x29\x28\x7A\x29" "\x3A\x3A\x3D\x3D\x3D\xE2\xB5\xA1\xE6\xAF\x8D\xE9\xBE\x9F\xE4\xB8\x80\xE4\xB8\xA8\xE4\xB8\xB6\xE4\xB8" "\xBF\xE4\xB9\x99\xE4\xBA\x85\xE4\xBA\x8C\xE4\xBA\xA0\xE4\xBA\xBA\xE5\x84\xBF\xE5\x85\xA5\xE5\x85\xAB" "\xE5\x86\x82\xE5\x86\x96\xE5\x86\xAB\xE5\x87\xA0\xE5\x88\x80\xE5\x8B\xB9\xE5\x8C\x95\xE5\x8C\x9A\xE5" "\x8C\xB8\xE5\x8D\x81\xE5\x8D\x9C\xE5\x8D\xA9\xE5\x8E\x82\xE5\x8E\xB6\xE5\x8F\x88\xE5\x8F\xA3\xE5\x9B" "\x97\xE5\x9C\x9F\xE5\xA3\xAB\xE5\xA4\x82\xE5\xA4\x8A\xE5\xA4\x95\xE5\xA4\xA7\xE5\xAD\x90\xE5\xAE\x80" "\xE5\xAF\xB8\xE5\xB0\x8F\xE5\xB0\xB8\xE5\xB1\xB1\xE5\xB7\x9B\xE5\xB7\xA5\xE5\xB7\xB1\xE5\xB7\xBE\xE5" "\xB9\xB2\xE5\xB9\xBA\xE5\xB9\xBF\xE5\xBB\xB4\xE5\xBC\x8B\xE5\xBC\x93\xE5\xBD\x90\xE5\xBD\xA1\xE5\xBD" "\xB3\xE5\xBF\x83\xE6\x88\x88\xE6\x88\xB6\xE6\x89\x8B\xE6\x94\xAF\xE6\x94\xB4\xE6\x96\x87\xE6\x96\x97" "\xE6\x96\xA4\xE6\x96\xB9\xE6\x97\xA0\xE6\x97\xA5\xE6\x9B\xB0\xE6\x9C\x88\xE6\x9C\xA8\xE6\xAC\xA0\xE6" "\xAD\xA2\xE6\xAE\xB3\xE6\xAF\x8B\xE6\xAF\x94\xE6\xAF\x9B\xE6\xB0\x8F\xE6\xB0\x94\xE6\xB0\xB4\xE7\x81" "\xAB\xE7\x88\xAA\xE7\x88\xB6\xE7\x88\xBB\xE7\x88\xBF\xE7\x89\x87\xE7\x89\x99\xE7\x89\x9B\xE7\x8A\xAC" "\xE7\x8E\x84\xE7\x8E\x89\xE7\x93\x9C\xE7\x93\xA6\xE7\x94\x98\xE7\x94\x9F\xE7\x94\xA8\xE7\x94\xB0\xE7" "\x96\x8B\xE7\x96\x92\xE7\x99\xB6\xE7\x99\xBD\xE7\x9A\xAE\xE7\x9A\xBF\xE7\x9B\xAE\xE7\x9F\x9B\xE7\x9F" "\xA2\xE7\x9F\xB3\xE7\xA4\xBA\xE7\xA6\xB8\xE7\xA6\xBE\xE7\xA9\xB4\xE7\xAB\xB9\xE7\xB1\xB3\xE7\xB3\xB8" "\xE7\xBC\xB6\xE7\xBD\x91\xE7\xBE\x8A\xE8\x80\x8C\xE8\x80\x92\xE8\x80\xB3\xE8\x81\xBF\xE8\x82\x89\xE8" "\x87\xA3\xE8\x87\xAA\xE8\x87\xB3\xE8\x87\xBC\xE8\x88\x8C\xE8\x88\x9B\xE8\x88\x9F\xE8\x89\xAE\xE8\x89" "\xB2\xE8\x89\xB8\xE8\x99\x8D\xE8\x99\xAB\xE8\xA1\x80\xE8\xA5\xBE\xE8\xA7\x92\xE8\xA8\x80\xE8\xB0\xB7" "\xE8\xB1\x86\xE8\xB1\xB8\xE8\xB2\x9D\xE8\xB5\xA4\xE8\xB5\xB0\xE8\xB6\xB3\xE8\xBA\xAB\xE8\xBE\x9B\xE8" "\xBE\xB5\xE9\x82\x91\xE9\x85\x89\xE9\x87\x86\xE9\x95\xB7\xE9\x96\x80\xE9\x98\x9C\xE9\x9A\xB6\xE9\x9A" "\xB9\xE9\x9B\xA8\xE9\x9D\x91\xE9\x9D\x9E\xE9\x9D\xA2\xE9\x9D\xA9\xE9\x9F\x8B\xE9\x9F\xAD\xE9\x9F\xB3" "\xE9\xA0\x81\xE9\xA2\xA8\xE9\xA3\x9B\xE9\xA3\x9F\xE9\xA6\x96\xE9\xA6\x99\xE9\xA6\xAC\xE9\xAA\xA8\xE9" "\xAB\x98\xE9\xAB\x9F\xE9\xAC\xA5\xE9\xAC\xAF\xE9\xAC\xB2\xE9\xAC\xBC\xE9\xAD\x9A\xE9\xB3\xA5\xE9\xB9" "\xB5\xE9\xBA\xA5\xE9\xBB\x83\xE9\xBB\x8D\xE9\xBB\x91\xE9\xBB\xBD\xE9\xBC\x8E\xE9\xBC\x93\xE9\xBC\xA0" "\xE9\xBD\x8A\xE9\xBD\x92\xE9\xBE\xA0\xE3\x80\x92\xE5\x8D\x84\xE5\x8D\x85\x20\xE3\x82\x99\x20\xE3\x82" "\x9A\xE3\x82\x88\xE3\x82\x8A\xE3\x82\xB3\xE3\x83\x88\xE1\x84\x80\xE1\x84\x81\xE1\x86\xAA\xE1\x84\x82" "\xE1\x86\xAC\xE1\x86\xAD\xE1\x84\x83\xE1\x84\x84\xE1\x84\x85\xE1\x86\xB0\xE1\x86\xB1\xE1\x86\xB2\xE1" "\x86\xB3\xE1\x86\xB4\xE1\x86\xB5\xE1\x84\x9A\xE1\x84\x86\xE1\x84\x87\xE1\x84\x88\xE1\x84\xA1\xE1\x84" "\x89\xE1\x84\x8A\xE1\x84\x8B\xE1\x84\x8C\xE1\x84\x8D\xE1\x84\x8E\xE1\x84\x8F\xE1\x84\x90\xE1\x84\x91" "\xE1\x84\x92\xE1\x85\xA1\xE1\x85\xA2\xE1\x85\xA3\xE1\x85\xA4\xE1\x85\xA5\xE1\x85\xA6\xE1\x85\xA7\xE1" "\x85\xA8\xE1\x85\xA9\xE1\x85\xAA\xE1\x85\xAB\xE1\x85\xAC\xE1\x85\xAD\xE1\x85\xAE\xE1\x85\xAF\xE1\x85" "\xB0\xE1\x85\xB1\xE1\x85\xB2\xE1\x85\xB3\xE1\x85\xB4\xE1\x85\xB5\xE1\x85\xA0\xE1\x84\x94\xE1\x84\x95" "\xE1\x87\x87\xE1\x87\x88\xE1\x87\x8C\xE1\x87\x8E\xE1\x87\x93\xE1\x87\x97\xE1\x87\x99\xE1\x84\x9C\xE1" "\x87\x9D\xE1\x87\x9F\xE1\x84\x9D\xE1\x84\x9E\xE1\x84\xA0\xE1\x84\xA2\xE1\x84\xA3\xE1\x84\xA7\xE1\x84" "\xA9\xE1\x84\xAB\xE1\x84\xAC\xE1\x84\xAD\xE1\x84\xAE\xE1\x84\xAF\xE1\x84\xB2\xE1\x84\xB6\xE1\x85\x80" "\xE1\x85\x87\xE1\x85\x8C\xE1\x87\xB1\xE1\x87\xB2\xE1\x85\x97\xE1\x85\x98\xE1\x85\x99\xE1\x86\x84\xE1" "\x86\x85\xE1\x86\x88\xE1\x86\x91\xE1\x86\x92\xE1\x86\x94\xE1\x86\x9E\xE1\x86\xA1\xE4\xB8\x89\xE5\x9B" "\x9B\xE4\xB8\x8A\xE4\xB8\xAD\xE4\xB8\x8B\xE7\x94\xB2\xE4\xB8\x99\xE4\xB8\x81\xE5\xA4\xA9\xE5\x9C\xB0" "\x28\xE1\x84\x80\x29\x28\xE1\x84\x82\x29\x28\xE1\x84\x83\x29\x28\xE1\x84\x85\x29\x28\xE1\x84\x86\x29" "\x28\xE1\x84\x87\x29\x28\xE1\x84\x89\x29\x28\xE1\x84\x8B\x29\x28\xE1\x84\x8C\x29\x28\xE1\x84\x8E\x29" "\x28\xE1\x84\x8F\x29\x28\xE1\x84\x90\x29\x28\xE1\x84\x91\x29\x28\xE1\x84\x92\x29\x28\xE1\x84\x80\xE1" "\x85\xA1\x29\x28\xE1\x84\x82\xE1\x85\xA1\x29\x28\xE1\x84\x83\xE1\x85\xA1\x29\x28\xE1\x84\x85\xE1\x85" "\xA1\x29\x28\xE1\x84\x86\xE1\x85\xA1\x29\x28\xE1\x84\x87\xE1\x85\xA1\x29\x28\xE1\x84\x89\xE1\x85\xA1" "\x29\x28\xE1\x84\x8B\xE1\x85\xA1\x29\x28\xE1\x84\x8C\xE1\x85\xA1\x29\x28\xE1\x84\x8E\xE1\x85\xA1\x29" "\x28\xE1\x84\x8F\xE1\x85\xA1\x29\x28\xE1\x84\x90\xE1\x85\xA1\x29\x28\xE1\x84\x91\xE1\x85\xA1\x29\x28" "\xE1\x84\x92\xE1\x85\xA1\x29\x28\xE1\x84\x8C\xE1\x85\xAE\x29\x28\xE1\x84\x8B\xE1\x85\xA9\xE1\x84\x8C" "\xE1\x85\xA5\xE1\x86\xAB\x29\x28\xE1\x84\x8B\xE1\x85\xA9\xE1\x84\x92\xE1\x85\xAE\x29\x28\xE4\xB8\x80" "\x29\x28\xE4\xBA\x8C\x29\x28\xE4\xB8\x89\x29\x28\xE5\x9B\x9B\x29\x28\xE4\xBA\x94\x29\x28\xE5\x85\xAD" "\x29\x28\xE4\xB8\x83\x29\x28\xE5\x85\xAB\x29\x28\xE4\xB9\x9D\x29\x28\xE5\x8D\x81\x29\x28\xE6\x9C\x88" "\x29\x28\xE7\x81\xAB\x29\x28\xE6\xB0\xB4\x29\x28\xE6\x9C\xA8\x29\x28\xE9\x87\x91\x29\x28\xE5\x9C\x9F" "\x29\x28\xE6\x97\xA5\x29\x28\xE6\xA0\xAA\x29\x28\xE6\x9C\x89\x29\x28\xE7\xA4\xBE\x29\x28\xE5\x90\x8D" "\x29\x28\xE7\x89\xB9\x29\x28\xE8\xB2\xA1\x29\x28\xE7\xA5\x9D\x29\x28\xE5\x8A\xB4\x29\x28\xE4\xBB\xA3" "\x29\x28\xE5\x91\xBC\x29\x28\xE5\xAD\xA6\x29\x28\xE7\x9B\xA3\x29\x28\xE4\xBC\x81\x29\x28\xE8\xB3\x87" "\x29\x28\xE5\x8D\x94\x29\x28\xE7\xA5\xAD\x29\x28\xE4\xBC\x91\x29\x28\xE8\x87\xAA\x29\x28\xE8\x87\xB3" "\x29\xE5\x95\x8F\xE5\xB9\xBC\xE7\xAE\x8F\x50\x54\x45\x32\x32\x32\x34\x32\x35\x32\x36\x32\x37\x32\x38" "\x32\x39\x33\x30\x33\x33\x33\x34\x33\x35\xE1\x84\x8E\xE1\x85\xA1\xE1\x86\xB7\xE1\x84\x80\xE1\x85\xA9" "\xE1\x84\x8C\xE1\x85\xAE\xE1\x84\x8B\xE1\x85\xB4\xE1\x84\x8B\xE1\x85\xAE\xE7\xA7\x98\xE7\x94\xB7\xE9" "\x81\xA9\xE5\x84\xAA\xE5\x8D\xB0\xE6\xB3\xA8\xE9\xA0\x85\xE5\x86\x99\xE6\xAD\xA3\xE5\xB7\xA6\xE5\x8F" "\xB3\xE5\x8C\xBB\xE5\xAE\x97\xE5\xA4\x9C\x33\x36\x33\x37\x33\x38\x33\x39\x34\x30\x34\x34\x34\x35\x34" "\x36\x34\x37\x34\x38\x34\x39\x35\x30\x31\xE6\x9C\x88\x32\xE6\x9C\x88\x33\xE6\x9C\x88\x34\xE6\x9C\x88" "\x35\xE6\x9C\x88\x36\xE6\x9C\x88\x37\xE6\x9C\x88\x38\xE6\x9C\x88\x39\xE6\x9C\x88\x31\x30\xE6\x9C\x88" "\x31\x31\xE6\x9C\x88\x31\x32\xE6\x9C\x88\x48\x67\x65\x72\x67\x65\x56\x4C\x54\x44\xE3\x82\xA2\xE3\x82" "\xA4\xE3\x82\xA8\xE3\x82\xAA\xE3\x83\x8A\xE3\x83\x8B\xE3\x83\x8C\xE3\x83\x8D\xE3\x83\x8E\xE3\x83\x9E" "\xE3\x83\x9F\xE3\x83\xA0\xE3\x83\xA1\xE3\x83\xA2\xE3\x83\xA4\xE3\x83\xA6\xE3\x83\xA8\xE3\x83\xA9\xE3" "\x83\xAA\xE3\x83\xAB\xE3\x83\xAC\xE3\x83\xAD\xE3\x82\xA2\xE3\x83\x8F\xE3\x82\x9A\xE3\x83\xBC\xE3\x83" "\x88\xE3\x82\xA2\xE3\x83\xAB\xE3\x83\x95\xE3\x82\xA1\xE3\x82\xA2\xE3\x83\xB3\xE3\x83\x98\xE3\x82\x9A" "\xE3\x82\xA2\xE3\x82\xA2\xE3\x83\xBC\xE3\x83\xAB\xE3\x82\xA4\xE3\x83\x8B\xE3\x83\xB3\xE3\x82\xAF\xE3" "\x82\x99\xE3\x82\xA4\xE3\x83\xB3\xE3\x83\x81\xE3\x82\xA6\xE3\x82\xA9\xE3\x83\xB3\xE3\x82\xA8\xE3\x82" "\xB9\xE3\x82\xAF\xE3\x83\xBC\xE3\x83\x88\xE3\x82\x99\xE3\x82\xA8\xE3\x83\xBC\xE3\x82\xAB\xE3\x83\xBC" "\xE3\x82\xAA\xE3\x83\xB3\xE3\x82\xB9\xE3\x82\xAA\xE3\x83\xBC\xE3\x83\xA0\xE3\x82\xAB\xE3\x82\xA4\xE3" "\x83\xAA\xE3\x82\xAB\xE3\x83\xA9\xE3\x83\x83\xE3\x83\x88\xE3\x82\xAB\xE3\x83\xAD\xE3\x83\xAA\xE3\x83" "\xBC\xE3\x82\xAB\xE3\x82\x99\xE3\x83\xAD\xE3\x83\xB3\xE3\x82\xAB\xE3\x82\x99\xE3\x83\xB3\xE3\x83\x9E" "\xE3\x82\xAD\xE3\x82\x99\xE3\x82\xAB\xE3\x82\x99\xE3\x82\xAD\xE3\x82\x99\xE3\x83\x8B\xE3\x83\xBC\xE3" "\x82\xAD\xE3\x83\xA5\xE3\x83\xAA\xE3\x83\xBC\xE3\x82\xAD\xE3\x82\x99\xE3\x83\xAB\xE3\x82\xBF\xE3\x82" "\x99\xE3\x83\xBC\xE3\x82\xAD\xE3\x83\xAD\xE3\x82\xAD\xE3\x83\xAD\xE3\x82\xAF\xE3\x82\x99\xE3\x83\xA9" "\xE3\x83\xA0\xE3\x82\xAD\xE3\x83\xAD\xE3\x83\xA1\xE3\x83\xBC\xE3\x83\x88\xE3\x83\xAB\xE3\x82\xAD\xE3" "\x83\xAD\xE3\x83\xAF\xE3\x83\x83\xE3\x83\x88\xE3\x82\xAF\xE3\x82\x99\xE3\x83\xA9\xE3\x83\xA0\xE3\x83" "\x88\xE3\x83\xB3\xE3\x82\xAF\xE3\x83\xAB\xE3\x82\xBB\xE3\x82\x99\xE3\x82\xA4\xE3\x83\xAD\xE3\x82\xAF" "\xE3\x83\xAD\xE3\x83\xBC\xE3\x83\x8D\xE3\x82\xB1\xE3\x83\xBC\xE3\x82\xB9\xE3\x82\xB3\xE3\x83\xAB\xE3" "\x83\x8A\xE3\x82\xB3\xE3\x83\xBC\xE3\x83\x9B\xE3\x82\x9A\xE3\x82\xB5\xE3\x82\xA4\xE3\x82\xAF\xE3\x83" "\xAB\xE3\x82\xB5\xE3\x83\xB3\xE3\x83\x81\xE3\x83\xBC\xE3\x83\xA0\xE3\x82\xB7\xE3\x83\xAA\xE3\x83\xB3" "\xE3\x82\xAF\xE3\x82\x99\xE3\x82\xBB\xE3\x83\xB3\xE3\x83\x81\xE3\x82\xBB\xE3\x83\xB3\xE3\x83\x88\xE3" "\x82\xBF\xE3\x82\x99\xE3\x83\xBC\xE3\x82\xB9\xE3\x83\x86\xE3\x82\x99\xE3\x82\xB7\xE3\x83\x88\xE3\x82" "\x99\xE3\x83\xAB\xE3\x83\x8A\xE3\x83\x8E\xE3\x83\x8E\xE3\x83\x83\xE3\x83\x88\xE3\x83\x8F\xE3\x82\xA4" "\xE3\x83\x84\xE3\x83\x8F\xE3\x82\x9A\xE3\x83\xBC\xE3\x82\xBB\xE3\x83\xB3\xE3\x83\x88\xE3\x83\x8F\xE3" "\x82\x9A\xE3\x83\xBC\xE3\x83\x84\xE3\x83\x8F\xE3\x82\x99\xE3\x83\xBC\xE3\x83\xAC\xE3\x83\xAB\xE3\x83" "\x92\xE3\x82\x9A\xE3\x82\xA2\xE3\x82\xB9\xE3\x83\x88\xE3\x83\xAB\xE3\x83\x92\xE3\x82\x9A\xE3\x82\xAF" "\xE3\x83\xAB\xE3\x83\x92\xE3\x82\x9A\xE3\x82\xB3\xE3\x83\x92\xE3\x82\x99\xE3\x83\xAB\xE3\x83\x95\xE3" "\x82\xA1\xE3\x83\xA9\xE3\x83\x83\xE3\x83\x88\xE3\x82\x99\xE3\x83\x95\xE3\x82\xA3\xE3\x83\xBC\xE3\x83" "\x88\xE3\x83\x95\xE3\x82\x99\xE3\x83\x83\xE3\x82\xB7\xE3\x82\xA7\xE3\x83\xAB\xE3\x83\x95\xE3\x83\xA9" "\xE3\x83\xB3\xE3\x83\x98\xE3\x82\xAF\xE3\x82\xBF\xE3\x83\xBC\xE3\x83\xAB\xE3\x83\x98\xE3\x82\x9A\xE3" "\x82\xBD\xE3\x83\x98\xE3\x82\x9A\xE3\x83\x8B\xE3\x83\x92\xE3\x83\x98\xE3\x83\xAB\xE3\x83\x84\xE3\x83" "\x98\xE3\x82\x9A\xE3\x83\xB3\xE3\x82\xB9\xE3\x83\x98\xE3\x82\x9A\xE3\x83\xBC\xE3\x82\xB7\xE3\x82\x99" "\xE3\x83\x98\xE3\x82\x99\xE3\x83\xBC\xE3\x82\xBF\xE3\x83\x9B\xE3\x82\x9A\xE3\x82\xA4\xE3\x83\xB3\xE3" "\x83\x88\xE3\x83\x9B\xE3\x82\x99\xE3\x83\xAB\xE3\x83\x88\xE3\x83\x9B\xE3\x83\xB3\xE3\x83\x9B\xE3\x82" "\x9A\xE3\x83\xB3\xE3\x83\x88\xE3\x82\x99\xE3\x83\x9B\xE3\x83\xBC\xE3\x83\xAB\xE3\x83\x9B\xE3\x83\xBC" "\xE3\x83\xB3\xE3\x83\x9E\xE3\x82\xA4\xE3\x82\xAF\xE3\x83\xAD\xE3\x83\x9E\xE3\x82\xA4\xE3\x83\xAB\xE3" "\x83\x9E\xE3\x83\x83\xE3\x83\x8F\xE3\x83\x9E\xE3\x83\xAB\xE3\x82\xAF\xE3\x83\x9E\xE3\x83\xB3\xE3\x82" "\xB7\xE3\x83\xA7\xE3\x83\xB3\xE3\x83\x9F\xE3\x82\xAF\xE3\x83\xAD\xE3\x83\xB3\xE3\x83\x9F\xE3\x83\xAA" "\xE3\x83\x9F\xE3\x83\xAA\xE3\x83\x8F\xE3\x82\x99\xE3\x83\xBC\xE3\x83\xAB\xE3\x83\xA1\xE3\x82\xAB\xE3" "\x82\x99\xE3\x83\xA1\xE3\x82\xAB\xE3\x82\x99\xE3\x83\x88\xE3\x83\xB3\xE3\x83\xA4\xE3\x83\xBC\xE3\x83" "\x88\xE3\x82\x99\xE3\x83\xA4\xE3\x83\xBC\xE3\x83\xAB\xE3\x83\xA6\xE3\x82\xA2\xE3\x83\xB3\xE3\x83\xAA" "\xE3\x83\x83\xE3\x83\x88\xE3\x83\xAB\xE3\x83\xAA\xE3\x83\xA9\xE3\x83\xAB\xE3\x83\x92\xE3\x82\x9A\xE3" "\x83\xBC\xE3\x83\xAB\xE3\x83\xBC\xE3\x83\x95\xE3\x82\x99\xE3\x83\xAB\xE3\x83\xAC\xE3\x83\xA0\xE3\x83" "\xAC\xE3\x83\xB3\xE3\x83\x88\xE3\x82\xB1\xE3\x82\x99\xE3\x83\xB3\x30\xE7\x82\xB9\x31\xE7\x82\xB9\x32" "\xE7\x82\xB9\x33\xE7\x82\xB9\x34\xE7\x82\xB9\x35\xE7\x82\xB9\x36\xE7\x82\xB9\x37\xE7\x82\xB9\x38\xE7" "\x82\xB9\x39\xE7\x82\xB9\x31\x30\xE7\x82\xB9\x31\x31\xE7\x82\xB9\x31\x32\xE7\x82\xB9\x31\x33\xE7\x82" "\xB9\x31\x34\xE7\x82\xB9\x31\x35\xE7\x82\xB9\x31\x36\xE7\x82\xB9\x31\x37\xE7\x82\xB9\x31\x38\xE7\x82" "\xB9\x31\x39\xE7\x82\xB9\x32\x30\xE7\x82\xB9\x32\x31\xE7\x82\xB9\x32\x32\xE7\x82\xB9\x32\x33\xE7\x82" "\xB9\x32\x34\xE7\x82\xB9\x68\x50\x61\x64\x61\x41\x55\x62\x61\x72\x6F\x56\x70\x63\x64\x6D\x64\x6D\x32" "\x64\x6D\x33\x49\x55\xE5\xB9\xB3\xE6\x88\x90\xE6\x98\xAD\xE5\x92\x8C\xE5\xA4\xA7\xE6\xAD\xA3\xE6\x98" "\x8E\xE6\xB2\xBB\xE6\xA0\xAA\xE5\xBC\x8F\xE4\xBC\x9A\xE7\xA4\xBE\x70\x41\x6E\x41\xCE\xBC\x41\x6D\x41" "\x6B\x41\x4B\x42\x4D\x42\x47\x42\x63\x61\x6C\x6B\x63\x61\x6C\x70\x46\x6E\x46\xCE\xBC\x46\xCE\xBC\x67" "\x6D\x67\x6B\x67\x48\x7A\x6B\x48\x7A\x4D\x48\x7A\x47\x48\x7A\x54\x48\x7A\xCE\xBC\x6C\x6D\x6C\x64\x6C" "\x6B\x6C\x66\x6D\x6E\x6D\xCE\xBC\x6D\x6D\x6D\x63\x6D\x6B\x6D\x6D\x6D\x32\x63\x6D\x32\x6B\x6D\x32\x6D" "\x6D\x33\x63\x6D\x33\x6B\x6D\x33\x6D\xE2\x88\x95\x73\x6D\xE2\x88\x95\x73\x32\x6B\x50\x61\x4D\x50\x61" "\x47\x50\x61\x72\x61\x64\x72\x61\x64\xE2\x88\x95\x73\x72\x61\x64\xE2\x88\x95\x73\x32\x70\x73\x6E\x73" "\xCE\xBC\x73\x6D\x73\x70\x56\x6E\x56\xCE\xBC\x56\x6D\x56\x6B\x56\x4D\x56\x70\x57\x6E\x57\xCE\xBC\x57" "\x6D\x57\x6B\x57\x4D\x57\x6B\xCE\xA9\x4D\xCE\xA9\x61\x2E\x6D\x2E\x42\x71\x63\x63\x43\xE2\x88\x95\x6B" "\x67\x43\x6F\x2E\x64\x42\x47\x79\x68\x61\x48\x50\x69\x6E\x4B\x4B\x4B\x4D\x6B\x74\x6C\x6E\x6C\x6F\x67" "\x6C\x78\x6D\x62\x6D\x69\x6C\x6D\x6F\x6C\x50\x48\x70\x2E\x6D\x2E\x50\x50\x4D\x50\x52\x53\x76\x57\x62" "\x56\xE2\x88\x95\x6D\x41\xE2\x88\x95\x6D\x31\xE6\x97\xA5\x32\xE6\x97\xA5\x33\xE6\x97\xA5\x34\xE6\x97" "\xA5\x35\xE6\x97\xA5\x36\xE6\x97\xA5\x37\xE6\x97\xA5\x38\xE6\x97\xA5\x39\xE6\x97\xA5\x31\x30\xE6\x97" "\xA5\x31\x31\xE6\x97\xA5\x31\x32\xE6\x97\xA5\x31\x33\xE6\x97\xA5\x31\x34\xE6\x97\xA5\x31\x35\xE6\x97" "\xA5\x31\x36\xE6\x97\xA5\x31\x37\xE6\x97\xA5\x31\x38\xE6\x97\xA5\x31\x39\xE6\x97\xA5\x32\x30\xE6\x97" "\xA5\x32\x31\xE6\x97\xA5\x32\x32\xE6\x97\xA5\x32\x33\xE6\x97\xA5\x32\x34\xE6\x97\xA5\x32\x35\xE6\x97" "\xA5\x32\x36\xE6\x97\xA5\x32\x37\xE6\x97\xA5\x32\x38\xE6\x97\xA5\x32\x39\xE6\x97\xA5\x33\x30\xE6\x97" "\xA5\x33\x31\xE6\x97\xA5\x67\x61\x6C\xD1\x8A\xD1\x8C\xEA\x9D\xAF\xC4\xA6\xC5\x93\xEA\x9C\xA7\xEA\xAC" "\xB7\xC9\xAB\xEA\xAD\x92\x66\x66\x66\x69\x66\x6C\x66\x66\x69\x66\x66\x6C\x73\x74\xD5\xB4\xD5\xB6\xD5" "\xB4\xD5\xA5\xD5\xB4\xD5\xAB\xD5\xBE\xD5\xB6\xD5\xB4\xD5\xAD\xD7\xA2\xD7\x9D\xD7\x90\xD7\x9C\xD9\xB1" "\xD9\xBB\xD9\xBE\xDA\x80\xD9\xBA\xD9\xBF\xD9\xB9\xDA\xA4\xDA\xA6\xDA\x84\xDA\x83\xDA\x86\xDA\x87\xDA" "\x8D\xDA\x8C\xDA\x8E\xDA\x88\xDA\x98\xDA\x91\xDA\xA9\xDA\xAF\xDA\xB3\xDA\xB1\xDA\xBA\xDA\xBB\xDA\xBE" "\xDA\xAD\xDB\x86\xDB\x88\xDB\x8B\xDB\x85\xDB\x89\xDB\x90\xD9\x89\xD9\x8A\xD9\x94\xD8\xA7\xD9\x8A\xD9" "\x94\xD9\x88\xD9\x8A\xD9\x94\xDB\x87\xD9\x8A\xD9\x94\xDB\x86\xD9\x8A\xD9\x94\xDB\x88\xD9\x8A\xD9\x94" "\xDB\x90\xD9\x8A\xD9\x94\xD9\x89\xDB\x8C\xD9\x8A\xD9\x94\xD8\xAC\xD9\x8A\xD9\x94\xD8\xAD\xD9\x8A\xD9" "\x94\xD9\x85\xD9\x8A\xD9\x94\xD9\x8A\xD8\xA8\xD8\xAC\xD8\xA8\xD8\xAD\xD8\xA8\xD8\xAE\xD8\xA8\xD9\x85" "\xD8\xA8\xD9\x89\xD8\xA8\xD9\x8A\xD8\xAA\xD8\xAC\xD8\xAA\xD8\xAD\xD8\xAA\xD8\xAE\xD8\xAA\xD9\x85\xD8" "\xAA\xD9\x89\xD8\xAA\xD9\x8A\xD8\xAB\xD8\xAC\xD8\xAB\xD9\x85\xD8\xAB\xD9\x89\xD8\xAB\xD9\x8A\xD8\xAC" "\xD8\xAD\xD8\xAC\xD9\x85\xD8\xAD\xD9\x85\xD8\xAE\xD8\xAC\xD8\xAE\xD8\xAD\xD8\xAE\xD9\x85\xD8\xB3\xD8" "\xAC\xD8\xB3\xD8\xAD\xD8\xB3\xD8\xAE\xD8\xB3\xD9\x85\xD8\xB5\xD8\xAD\xD8\xB5\xD9\x85\xD8\xB6\xD8\xAC" "\xD8\xB6\xD8\xAD\xD8\xB6\xD8\xAE\xD8\xB6\xD9\x85\xD8\xB7\xD8\xAD\xD8\xB7\xD9\x85\xD8\xB8\xD9\x85\xD8" "\xB9\xD8\xAC\xD8\xB9\xD9\x85\xD8\xBA\xD8\xAC\xD8\xBA\xD9\x85\xD9\x81\xD8\xAC\xD9\x81\xD8\xAD\xD9\x81" "\xD8\xAE\xD9\x81\xD9\x85\xD9\x81\xD9\x89\xD9\x81\xD9\x8A\xD9\x82\xD8\xAD\xD9\x82\xD9\x85\xD9\x82\xD9" "\x89\xD9\x82\xD9\x8A\xD9\x83\xD8\xA7\xD9\x83\xD8\xAC\xD9\x83\xD8\xAD\xD9\x83\xD8\xAE\xD9\x83\xD9\x84" "\xD9\x83\xD9\x85\xD9\x83\xD9\x89\xD9\x83\xD9\x8A\xD9\x84\xD8\xAC\xD9\x84\xD8\xAD\xD9\x84\xD8\xAE\xD9" "\x84\xD9\x85\xD9\x84\xD9\x89\xD9\x84\xD9\x8A\xD9\x85\xD8\xAC\xD9\x85\xD9\x85\xD9\x85\xD9\x89\xD9\x86" "\xD8\xAC\xD9\x86\xD8\xAD\xD9\x86\xD8\xAE\xD9\x86\xD9\x85\xD9\x86\xD9\x89\xD9\x86\xD9\x8A\xD9\x87\xD8" "\xAC\xD9\x87\xD9\x85\xD9\x87\xD9\x89\xD9\x87\xD9\x8A\xD9\x8A\xD8\xAD\xD9\x8A\xD8\xAE\xD9\x8A\xD9\x89" "\xD8\xB0\xD9\xB0\xD8\xB1\xD9\xB0\xD9\x89\xD9\xB0\x20\xD9\x8C\xD9\x91\x20\xD9\x8D\xD9\x91\x20\xD9\x8E" "\xD9\x91\x20\xD9\x8F\xD9\x91\x20\xD9\x90\xD9\x91\x20\xD9\x91\xD9\xB0\xD9\x8A\xD9\x94\xD8\xB1\xD9\x8A" "\xD9\x94\xD8\xB2\xD9\x8A\xD9\x94\xD9\x86\xD8\xA8\xD8\xB1\xD8\xA8\xD8\xB2\xD8\xA8\xD9\x86\xD8\xAA\xD8" "\xB1\xD8\xAA\xD8\xB2\xD8\xAA\xD9\x86\xD8\xAB\xD8\xB1\xD8\xAB\xD8\xB2\xD8\xAB\xD9\x86\xD9\x85\xD8\xA7" "\xD9\x86\xD8\xB1\xD9\x86\xD8\xB2\xD9\x86\xD9\x86\xD9\x8A\xD8\xB1\xD9\x8A\xD8\xB2\xD9\x8A\xD9\x86\xD9" "\x8A\xD9\x94\xD8\xAE\xD9\x8A\xD9\x94\xD9\x87\xD8\xA8\xD9\x87\xD8\xAA\xD9\x87\xD8\xB5\xD8\xAE\xD9\x84" "\xD9\x87\xD9\x86\xD9\x87\xD9\x87\xD9\xB0\xD9\x8A\xD8\xAD\xD8\xAB\xD9\x87\xD8\xB3\xD9\x87\xD8\xB4\xD9" "\x85\xD8\xB4\xD9\x87\xD9\x80\xD9\x8E\xD9\x91\xD9\x80\xD9\x8F\xD9\x91\xD9\x80\xD9\x90\xD9\x91\xD8\xB7" "\xD9\x89\xD8\xB7\xD9\x8A\xD8\xB9\xD9\x89\xD8\xB9\xD9\x8A\xD8\xBA\xD9\x89\xD8\xBA\xD9\x8A\xD8\xB3\xD9" "\x89\xD8\xB3\xD9\x8A\xD8\xB4\xD9\x89\xD8\xB4\xD9\x8A\xD8\xAD\xD9\x89\xD8\xAC\xD9\x89\xD8\xAE\xD9\x89" "\xD8\xB5\xD9\x89\xD8\xB5\xD9\x8A\xD8\xB6\xD9\x89\xD8\xB6\xD9\x8A\xD8\xB4\xD8\xAC\xD8\xB4\xD8\xAD\xD8" "\xB4\xD8\xAE\xD8\xB4\xD8\xB1\xD8\xB3\xD8\xB1\xD8\xB5\xD8\xB1\xD8\xB6\xD8\xB1\xD8\xA7\xD9\x8B\xD8\xAA" "\xD8\xAC\xD9\x85\xD8\xAA\xD8\xAD\xD8\xAC\xD8\xAA\xD8\xAD\xD9\x85\xD8\xAA\xD8\xAE\xD9\x85\xD8\xAA\xD9" "\x85\xD8\xAC\xD8\xAA\xD9\x85\xD8\xAD\xD8\xAA\xD9\x85\xD8\xAE\xD8\xAD\xD9\x85\xD9\x8A\xD8\xAD\xD9\x85" "\xD9\x89\xD8\xB3\xD8\xAD\xD8\xAC\xD8\xB3\xD8\xAC\xD8\xAD\xD8\xB3\xD8\xAC\xD9\x89\xD8\xB3\xD9\x85\xD8" "\xAD\xD8\xB3\xD9\x85\xD8\xAC\xD8\xB3\xD9\x85\xD9\x85\xD8\xB5\xD8\xAD\xD8\xAD\xD8\xB5\xD9\x85\xD9\x85" "\xD8\xB4\xD8\xAD\xD9\x85\xD8\xB4\xD8\xAC\xD9\x8A\xD8\xB4\xD9\x85\xD8\xAE\xD8\xB4\xD9\x85\xD9\x85\xD8" "\xB6\xD8\xAD\xD9\x89\xD8\xB6\xD8\xAE\xD9\x85\xD8\xB7\xD9\x85\xD8\xAD\xD8\xB7\xD9\x85\xD9\x85\xD8\xB7" "\xD9\x85\xD9\x8A\xD8\xB9\xD8\xAC\xD9\x85\xD8\xB9\xD9\x85\xD9\x85\xD8\xB9\xD9\x85\xD9\x89\xD8\xBA\xD9" "\x85\xD9\x85\xD8\xBA\xD9\x85\xD9\x8A\xD8\xBA\xD9\x85\xD9\x89\xD9\x81\xD8\xAE\xD9\x85\xD9\x82\xD9\x85" "\xD8\xAD\xD9\x82\xD9\x85\xD9\x85\xD9\x84\xD8\xAD\xD9\x85\xD9\x84\xD8\xAD\xD9\x8A\xD9\x84\xD8\xAD\xD9" "\x89\xD9\x84\xD8\xAC\xD8\xAC\xD9\x84\xD8\xAE\xD9\x85\xD9\x84\xD9\x85\xD8\xAD\xD9\x85\xD8\xAD\xD8\xAC" "\xD9\x85\xD8\xAD\xD9\x8A\xD9\x85\xD8\xAC\xD8\xAD\xD9\x85\xD8\xAE\xD9\x85\xD9\x85\xD8\xAC\xD8\xAE\xD9" "\x87\xD9\x85\xD8\xAC\xD9\x87\xD9\x85\xD9\x85\xD9\x86\xD8\xAD\xD9\x85\xD9\x86\xD8\xAD\xD9\x89\xD9\x86" "\xD8\xAC\xD9\x85\xD9\x86\xD8\xAC\xD9\x89\xD9\x86\xD9\x85\xD9\x8A\xD9\x86\xD9\x85\xD9\x89\xD9\x8A\xD9" "\x85\xD9\x85\xD8\xA8\xD8\xAE\xD9\x8A\xD8\xAA\xD8\xAC\xD9\x8A\xD8\xAA\xD8\xAC\xD9\x89\xD8\xAA\xD8\xAE" "\xD9\x8A\xD8\xAA\xD8\xAE\xD9\x89\xD8\xAA\xD9\x85\xD9\x8A\xD8\xAA\xD9\x85\xD9\x89\xD8\xAC\xD9\x85\xD9" "\x8A\xD8\xAC\xD8\xAD\xD9\x89\xD8\xAC\xD9\x85\xD9\x89\xD8\xB3\xD8\xAE\xD9\x89\xD8\xB5\xD8\xAD\xD9\x8A" "\xD8\xB4\xD8\xAD\xD9\x8A\xD8\xB6\xD8\xAD\xD9\x8A\xD9\x84\xD8\xAC\xD9\x8A\xD9\x84\xD9\x85\xD9\x8A\xD9" "\x8A\xD8\xAD\xD9\x8A\xD9\x8A\xD8\xAC\xD9\x8A\xD9\x8A\xD9\x85\xD9\x8A\xD9\x85\xD9\x85\xD9\x8A\xD9\x82" "\xD9\x85\xD9\x8A\xD9\x86\xD8\xAD\xD9\x8A\xD8\xB9\xD9\x85\xD9\x8A\xD9\x83\xD9\x85\xD9\x8A\xD9\x86\xD8" "\xAC\xD8\xAD\xD9\x85\xD8\xAE\xD9\x8A\xD9\x84\xD8\xAC\xD9\x85\xD9\x83\xD9\x85\xD9\x85\xD8\xAC\xD8\xAD" "\xD9\x8A\xD8\xAD\xD8\xAC\xD9\x8A\xD9\x85\xD8\xAC\xD9\x8A\xD9\x81\xD9\x85\xD9\x8A\xD8\xA8\xD8\xAD\xD9" "\x8A\xD8\xB3\xD8\xAE\xD9\x8A\xD9\x86\xD8\xAC\xD9\x8A\xD8\xB5\xD9\x84\xDB\x92\xD9\x82\xD9\x84\xDB\x92" "\xD8\xA7\xD9\x84\xD9\x84\xD9\x87\xD8\xA7\xD9\x83\xD8\xA8\xD8\xB1\xD9\x85\xD8\xAD\xD9\x85\xD8\xAF\xD8" "\xB5\xD9\x84\xD8\xB9\xD9\x85\xD8\xB1\xD8\xB3\xD9\x88\xD9\x84\xD8\xB9\xD9\x84\xD9\x8A\xD9\x87\xD9\x88" "\xD8\xB3\xD9\x84\xD9\x85\xD8\xB5\xD9\x84\xD9\x89\xD8\xB5\xD9\x84\xD9\x89\x20\xD8\xA7\xD9\x84\xD9\x84" "\xD9\x87\x20\xD8\xB9\xD9\x84\xD9\x8A\xD9\x87\x20\xD9\x88\xD8\xB3\xD9\x84\xD9\x85\xD8\xAC\xD9\x84\x20" "\xD8\xAC\xD9\x84\xD8\xA7\xD9\x84\xD9\x87\xD8\xB1\xDB\x8C\xD8\xA7\xD9\x84\x2C\xE3\x80\x81\xE3\x80\x82" "\xE3\x80\x96\xE3\x80\x97\xE2\x80\x94\xE2\x80\x93\x5F\x7B\x7D\xE3\x80\x94\xE3\x80\x95\xE3\x80\x90\xE3" "\x80\x91\xE3\x80\x8A\xE3\x80\x8B\xE3\x80\x8C\xE3\x80\x8D\xE3\x80\x8E\xE3\x80\x8F\x5B\x5D\x23\x26\x2A" "\x2D\x5C\x24\x25\x40\x20\xD9\x8B\xD9\x80\xD9\x8B\xD9\x80\xD9\x91\x20\xD9\x92\xD9\x80\xD9\x92\xD8\xA1" "\xD8\xA9\xD9\x84\xD8\xA7\xD9\x93\xD9\x84\xD8\xA7\xD9\x94\xD9\x84\xD8\xA7\xD9\x95\x22\x27\x5E\x7C\x7E" "\xE2\xA6\x85\xE2\xA6\x86\xE3\x83\xBB\xE3\x82\xA5\xE3\x83\xA3\xC2\xA2\xC2\xA3\xC2\xAC\xC2\xA6\xC2\xA5" "\xE2\x82\xA9\xE2\x94\x82\xE2\x86\x91\xE2\x86\x93\xE2\x96\xA0\xE2\x97\x8B\xF0\x9D\x85\x98\xF0\x9D\x85" "\xA5\xF0\x9D\x85\xAE\xC4\xB1\xC8\xB7\xCE\x92\xCE\x94\xCE\x96\xCE\x9A\xCE\x9B\xCE\x9C\xCE\x9D\xCE\x9E" "\xCE\xA4\xCE\xA6\xCE\xA7\xCE\xA8\xE2\x88\x87\xCE\xB6\xCE\xBB\xCE\xBD\xCE\xBE\xCF\x83\xCF\x84\xCF\x88" "\xE2\x88\x82\xCF\x9C\xCF\x9D\xD9\xAE\xDA\xA1\xD9\xAF\x30\x2C\x31\x2C\x32\x2C\x33\x2C\x34\x2C\x35\x2C" "\x36\x2C\x37\x2C\x38\x2C\x39\x2C\x28\x41\x29\x28\x42\x29\x28\x43\x29\x28\x44\x29\x28\x45\x29\x28\x46" "\x29\x28\x47\x29\x28\x48\x29\x28\x49\x29\x28\x4A\x29\x28\x4B\x29\x28\x4C\x29\x28\x4D\x29\x28\x4E\x29" "\x28\x4F\x29\x28\x50\x29\x28\x51\x29\x28\x52\x29\x28\x53\x29\x28\x54\x29\x28\x55\x29\x28\x56\x29\x28" "\x57\x29\x28\x58\x29\x28\x59\x29\x28\x5A\x29\xE3\x80\x94\x53\xE3\x80\x95\x43\x44\x57\x5A\x48\x56\x53" "\x44\x53\x53\x50\x50\x56\x57\x43\x4D\x43\x4D\x44\x44\x4A\xE3\x81\xBB\xE3\x81\x8B\xE3\x82\xB3\xE3\x82" "\xB3\xE5\xAD\x97\xE5\x8F\x8C\xE8\xA7\xA3\xE4\xBA\xA4\xE6\x98\xA0\xE7\x84\xA1\xE5\x89\x8D\xE5\xBE\x8C" "\xE6\x96\xB0\xE5\x88\x9D\xE7\xB5\x82\xE8\xB2\xA9\xE5\xA3\xB0\xE5\x90\xB9\xE6\xBC\x94\xE6\x8A\x95\xE6" "\x8D\x95\xE9\x81\x8A\xE6\x8C\x87\xE6\x89\x93\xE7\xA6\x81\xE7\xA9\xBA\xE5\x90\x88\xE6\xBA\x80\xE7\x94" "\xB3\xE5\x96\xB6\xE3\x80\x94\xE6\x9C\xAC\xE3\x80\x95\xE3\x80\x94\xE4\xB8\x89\xE3\x80\x95\xE3\x80\x94" "\xE4\xBA\x8C\xE3\x80\x95\xE3\x80\x94\xE5\xAE\x89\xE3\x80\x95\xE3\x80\x94\xE7\x82\xB9\xE3\x80\x95\xE3" "\x80\x94\xE6\x89\x93\xE3\x80\x95\xE3\x80\x94\xE7\x9B\x97\xE3\x80\x95\xE3\x80\x94\xE5\x8B\x9D\xE3\x80" "\x95\xE3\x80\x94\xE6\x95\x97\xE3\x80\x95\xE5\xBE\x97\xE5\x8F\xAF\xC3\x80\xC3\x81\xC3\x82\xC3\x83\xC3" "\x84\xC3\x85\xC3\x87\xC3\x88\xC3\x89\xC3\x8A\xC3\x8B\xC3\x8C\xC3\x8D\xC3\x8E\xC3\x8F\xC3\x90\xC3\x91" "\xC3\x92\xC3\x93\xC3\x94\xC3\x95\xC3\x96\xC3\x99\xC3\x9A\xC3\x9B\xC3\x9C\xC3\x9D\xC3\x9E\xC5\xB8\xC4" "\x80\xC4\x82\xC4\x84\xC4\x86\xC4\x88\xC4\x8A\xC4\x8C\xC4\x8E\xC4\x90\xC4\x92\xC4\x94\xC4\x96\xC4\x98" "\xC4\x9A\xC4\x9C\xC4\x9E\xC4\xA0\xC4\xA2\xC4\xA4\xC4\xA8\xC4\xAA\xC4\xAC\xC4\xAE\xC4\xB2\xC4\xB4\xC4" "\xB6\xC4\xB9\xC4\xBB\xC4\xBD\xC4\xBF\xC5\x81\xC5\x83\xC5\x85\xC5\x87\xCA\xBC\x4E\xC5\x8A\xC5\x8C\xC5" "\x8E\xC5\x90\xC5\x92\xC5\x94\xC5\x96\xC5\x98\xC5\x9A\xC5\x9C\xC5\x9E\xC5\xA0\xC5\xA2\xC5\xA4\xC5\xA6" "\xC5\xA8\xC5\xAA\xC5\xAC\xC5\xAE\xC5\xB0\xC5\xB2\xC5\xB4\xC5\xB6\xC5\xB9\xC5\xBB\xC5\xBD\xC9\x83\xC6" "\x82\xC6\x84\xC6\x87\xC6\x8B\xC6\x91\xC7\xB6\xC6\x98\xC8\xBD\xC8\xA0\xC6\xA0\xC6\xA2\xC6\xA4\xC6\xA7" "\xC6\xAC\xC6\xAF\xC6\xB3\xC6\xB5\xC6\xB8\xC6\xBC\xC7\xB7\xC7\x84\xC7\x87\xC7\x8A\xC7\x8D\xC7\x8F\xC7" "\x91\xC7\x93\xC7\x95\xC7\x97\xC7\x99\xC7\x9B\xC7\x9E\xC7\xA0\xC7\xA2\xC7\xA4\xC7\xA6\xC7\xA8\xC7\xAA" "\xC7\xAC\xC7\xAE\x4A\xCC\x8C\xC7\xB1\xC7\xB4\xC7\xB8\xC7\xBA\xC7\xBC\xC7\xBE\xC8\x80\xC8\x82\xC8\x84" "\xC8\x86\xC8\x88\xC8\x8A\xC8\x8C\xC8\x8E\xC8\x90\xC8\x92\xC8\x94\xC8\x96\xC8\x98\xC8\x9A\xC8\x9C\xC8" "\x9E\xC8\xA4\xC8\xA6\xC8\xA8\xC8\xAA\xC8\xAC\xC8\xAE\xC8\xB0\xC8\xB2\xC8\xBB\xE2\xB1\xBE\xE2\xB1\xBF" "\xC9\x81\xC9\x86\xC9\x88\xC9\x8A\xC9\x8C\xC9\x8E\xE2\xB1\xAF\xE2\xB1\xAD\xE2\xB1\xB0\xC6\x81\xC6\x86" "\xC6\x89\xC6\x8A\xC6\x8F\xEA\x9E\xAB\xC6\x93\xEA\x9E\xAC\xC6\x94\xEA\x9E\x8D\xEA\x9E\xAA\xC6\x97\xC6" "\x96\xE2\xB1\xA2\xEA\x9E\xAD\xC6\x9C\xE2\xB1\xAE\xC6\x9D\xC6\x9F\xE2\xB1\xA4\xC6\xA6\xC6\xA9\xEA\x9E" "\xB1\xC6\xAE\xC9\x84\xC6\xB1\xC6\xB2\xC9\x85\xEA\x9E\xB0\xCD\xB0\xCD\xB2\xCD\xB6\xCF\xBD\xCF\xBE\xCF" "\xBF\xCE\x99\xCC\x88\xCC\x81\xCE\x86\xCE\x88\xCE\x89\xCE\x8A\xCE\xA5\xCC\x88\xCC\x81\xCE\xAA\xCE\xAB" "\xCE\x8C\xCE\x8E\xCE\x8F\xCF\x8F\xCF\x98\xCF\x9A\xCF\x9E\xCF\xA0\xCF\xA2\xCF\xA4\xCF\xA6\xCF\xA8\xCF" "\xAA\xCF\xAC\xCF\xAE\xCF\xB9\xCD\xBF\xCF\xB7\xCF\xBA\xD0\x91\xD0\x92\xD0\x94\xD0\x99\xD0\x9B\xD0\x9C" "\xD0\x9D\xD0\x9F\xD0\xA0\xD0\xA1\xD0\xA2\xD0\xA4\xD0\xA5\xD0\xA6\xD0\xA8\xD0\xA9\xD0\xAA\xD0\xAC\xD0" "\xAE\xD0\xAF\xD0\x80\xD0\x81\xD0\x82\xD0\x83\xD0\x84\xD0\x85\xD0\x87\xD0\x88\xD0\x89\xD0\x8A\xD0\x8B" "\xD0\x8C\xD0\x8D\xD0\x8E\xD0\x8F\xD1\xA0\xD1\xA2\xD1\xA4\xD1\xA6\xD1\xA8\xD1\xAA\xD1\xAC\xD1\xAE\xD1" "\xB0\xD1\xB2\xD1\xB6\xD1\xB8\xD1\xBA\xD1\xBC\xD1\xBE\xD2\x80\xD2\x8A\xD2\x8C\xD2\x8E\xD2\x90\xD2\x92" "\xD2\x94\xD2\x96\xD2\x98\xD2\x9A\xD2\x9C\xD2\x9E\xD2\xA0\xD2\xA2\xD2\xA4\xD2\xA6\xD2\xA8\xD2\xAA\xD2" "\xAC\xD2\xAE\xD2\xB0\xD2\xB2\xD2\xB4\xD2\xB6\xD2\xB8\xD2\xBA\xD2\xBC\xD2\xBE\xD3\x81\xD3\x83\xD3\x85" "\xD3\x87\xD3\x89\xD3\x8B\xD3\x8D\xD3\x80\xD3\x90\xD3\x92\xD3\x94\xD3\x96\xD3\x9A\xD3\x9C\xD3\x9E\xD3" "\xA0\xD3\xA2\xD3\xA4\xD3\xA6\xD3\xAA\xD3\xAC\xD3\xAE\xD3\xB0\xD3\xB2\xD3\xB4\xD3\xB6\xD3\xB8\xD3\xBA" "\xD3\xBC\xD3\xBE\xD4\x80\xD4\x82\xD4\x84\xD4\x86\xD4\x88\xD4\x8A\xD4\x8C\xD4\x8E\xD4\x90\xD4\x92\xD4" "\x94\xD4\x96\xD4\x98\xD4\x9A\xD4\x9C\xD4\x9E\xD4\xA0\xD4\xA2\xD4\xA4\xD4\xA6\xD4\xA8\xD4\xAA\xD4\xAC" "\xD4\xAE\xD4\xB1\xD4\xB2\xD4\xB3\xD4\xB4\xD4\xB5\xD4\xB6\xD4\xB7\xD4\xB8\xD4\xB9\xD4\xBA\xD4\xBB\xD4" "\xBC\xD4\xBD\xD4\xBE\xD4\xBF\xD5\x80\xD5\x81\xD5\x82\xD5\x83\xD5\x84\xD5\x85\xD5\x86\xD5\x87\xD5\x88" "\xD5\x89\xD5\x8A\xD5\x8B\xD5\x8C\xD5\x8D\xD5\x8E\xD5\x8F\xD5\x90\xD5\x91\xD5\x92\xD5\x93\xD5\x94\xD5" "\x95\xD5\x96\xD4\xB5\xD5\x92\xEA\x9D\xBD\xE2\xB1\xA3\xE1\xB8\x80\xE1\xB8\x82\xE1\xB8\x84\xE1\xB8\x86" "\xE1\xB8\x88\xE1\xB8\x8A\xE1\xB8\x8C\xE1\xB8\x8E\xE1\xB8\x90\xE1\xB8\x92\xE1\xB8\x94\xE1\xB8\x96\xE1" "\xB8\x98\xE1\xB8\x9A\xE1\xB8\x9C\xE1\xB8\x9E\xE1\xB8\xA0\xE1\xB8\xA2\xE1\xB8\xA4\xE1\xB8\xA6\xE1\xB8" "\xA8\xE1\xB8\xAA\xE1\xB8\xAC\xE1\xB8\xAE\xE1\xB8\xB0\xE1\xB8\xB2\xE1\xB8\xB4\xE1\xB8\xB6\xE1\xB8\xB8" "\xE1\xB8\xBA\xE1\xB8\xBC\xE1\xB8\xBE\xE1\xB9\x80\xE1\xB9\x82\xE1\xB9\x84\xE1\xB9\x86\xE1\xB9\x88\xE1" "\xB9\x8A\xE1\xB9\x8C\xE1\xB9\x8E\xE1\xB9\x90\xE1\xB9\x92\xE1\xB9\x94\xE1\xB9\x96\xE1\xB9\x98\xE1\xB9" "\x9A\xE1\xB9\x9C\xE1\xB9\x9E\xE1\xB9\xA0\xE1\xB9\xA2\xE1\xB9\xA4\xE1\xB9\xA6\xE1\xB9\xA8\xE1\xB9\xAA" "\xE1\xB9\xAC\xE1\xB9\xAE\xE1\xB9\xB0\xE1\xB9\xB2\xE1\xB9\xB4\xE1\xB9\xB6\xE1\xB9\xB8\xE1\xB9\xBA\xE1" "\xB9\xBC\xE1\xB9\xBE\xE1\xBA\x80\xE1\xBA\x82\xE1\xBA\x84\xE1\xBA\x86\xE1\xBA\x88\xE1\xBA\x8A\xE1\xBA" "\x8C\xE1\xBA\x8E\xE1\xBA\x90\xE1\xBA\x92\xE1\xBA\x94\x48\xCC\xB1\x54\xCC\x88\x57\xCC\x8A\x59\xCC\x8A" "\x41\xCA\xBE\xE1\xBA\xA0\xE1\xBA\xA2\xE1\xBA\xA4\xE1\xBA\xA6\xE1\xBA\xA8\xE1\xBA\xAA\xE1\xBA\xAC\xE1" "\xBA\xAE\xE1\xBA\xB0\xE1\xBA\xB2\xE1\xBA\xB4\xE1\xBA\xB6\xE1\xBA\xB8\xE1\xBA\xBA\xE1\xBA\xBC\xE1\xBA" "\xBE\xE1\xBB\x80\xE1\xBB\x82\xE1\xBB\x84\xE1\xBB\x86\xE1\xBB\x88\xE1\xBB\x8A\xE1\xBB\x8C\xE1\xBB\x8E" "\xE1\xBB\x90\xE1\xBB\x92\xE1\xBB\x94\xE1\xBB\x96\xE1\xBB\x98\xE1\xBB\x9A\xE1\xBB\x9C\xE1\xBB\x9E\xE1" "\xBB\xA0\xE1\xBB\xA2\xE1\xBB\xA4\xE1\xBB\xA6\xE1\xBB\xA8\xE1\xBB\xAA\xE1\xBB\xAC\xE1\xBB\xAE\xE1\xBB" "\xB0\xE1\xBB\xB2\xE1\xBB\xB4\xE1\xBB\xB6\xE1\xBB\xB8\xE1\xBB\xBA\xE1\xBB\xBC\xE1\xBB\xBE\xE1\xBC\x88" "\xE1\xBC\x89\xE1\xBC\x8A\xE1\xBC\x8B\xE1\xBC\x8C\xE1\xBC\x8D\xE1\xBC\x8E\xE1\xBC\x8F\xE1\xBC\x98\xE1" "\xBC\x99\xE1\xBC\x9A\xE1\xBC\x9B\xE1\xBC\x9C\xE1\xBC\x9D\xE1\xBC\xA8\xE1\xBC\xA9\xE1\xBC\xAA\xE1\xBC" "\xAB\xE1\xBC\xAC\xE1\xBC\xAD\xE1\xBC\xAE\xE1\xBC\xAF\xE1\xBC\xB8\xE1\xBC\xB9\xE1\xBC\xBA\xE1\xBC\xBB" "\xE1\xBC\xBC\xE1\xBC\xBD\xE1\xBC\xBE\xE1\xBC\xBF\xE1\xBD\x88\xE1\xBD\x89\xE1\xBD\x8A\xE1\xBD\x8B\xE1" "\xBD\x8C\xE1\xBD\x8D\xCE\xA5\xCC\x93\xE1\xBD\x99\xCE\xA5\xCC\x93\xCC\x80\xE1\xBD\x9B\xCE\xA5\xCC\x93" "\xCC\x81\xE1\xBD\x9D\xCE\xA5\xCC\x93\xCD\x82\xE1\xBD\x9F\xE1\xBD\xA8\xE1\xBD\xA9\xE1\xBD\xAA\xE1\xBD" "\xAB\xE1\xBD\xAC\xE1\xBD\xAD\xE1\xBD\xAE\xE1\xBD\xAF\xE1\xBE\xBA\xE1\xBE\xBB\xE1\xBF\x88\xE1\xBF\x89" "\xE1\xBF\x8A\xE1\xBF\x8B\xE1\xBF\x9A\xE1\xBF\x9B\xE1\xBF\xB8\xE1\xBF\xB9\xE1\xBF\xAA\xE1\xBF\xAB\xE1" "\xBF\xBA\xE1\xBF\xBB\xE1\xBC\x88\xCE\x99\xE1\xBC\x89\xCE\x99\xE1\xBC\x8A\xCE\x99\xE1\xBC\x8B\xCE\x99" "\xE1\xBC\x8C\xCE\x99\xE1\xBC\x8D\xCE\x99\xE1\xBC\x8E\xCE\x99\xE1\xBC\x8F\xCE\x99\xE1\xBC\xA8\xCE\x99" "\xE1\xBC\xA9\xCE\x99\xE1\xBC\xAA\xCE\x99\xE1\xBC\xAB\xCE\x99\xE1\xBC\xAC\xCE\x99\xE1\xBC\xAD\xCE\x99" "\xE1\xBC\xAE\xCE\x99\xE1\xBC\xAF\xCE\x99\xE1\xBD\xA8\xCE\x99\xE1\xBD\xA9\xCE\x99\xE1\xBD\xAA\xCE\x99" "\xE1\xBD\xAB\xCE\x99\xE1\xBD\xAC\xCE\x99\xE1\xBD\xAD\xCE\x99\xE1\xBD\xAE\xCE\x99\xE1\xBD\xAF\xCE\x99" "\xE1\xBE\xB8\xE1\xBE\xB9\xE1\xBE\xBA\xCE\x99\xCE\x91\xCE\x99\xCE\x86\xCE\x99\xCE\x91\xCD\x82\xCE\x91" "\xCD\x82\xCE\x99\xE1\xBF\x8A\xCE\x99\xCE\x97\xCE\x99\xCE\x89\xCE\x99\xCE\x97\xCD\x82\xCE\x97\xCD\x82" "\xCE\x99\xE1\xBF\x98\xE1\xBF\x99\xCE\x99\xCC\x88\xCC\x80\xCE\x99\xCD\x82\xCE\x99\xCC\x88\xCD\x82\xE1" "\xBF\xA8\xE1\xBF\xA9\xCE\xA5\xCC\x88\xCC\x80\xCE\xA1\xCC\x93\xE1\xBF\xAC\xCE\xA5\xCD\x82\xCE\xA5\xCC" "\x88\xCD\x82\xE1\xBF\xBA\xCE\x99\xCE\xA9\xCE\x99\xCE\x8F\xCE\x99\xCE\xA9\xCD\x82\xCE\xA9\xCD\x82\xCE" "\x99\xE2\x84\xB2\xE2\x85\xA0\xE2\x85\xA1\xE2\x85\xA2\xE2\x85\xA3\xE2\x85\xA4\xE2\x85\xA5\xE2\x85\xA6" "\xE2\x85\xA7\xE2\x85\xA8\xE2\x85\xA9\xE2\x85\xAA\xE2\x85\xAB\xE2\x85\xAC\xE2\x85\xAD\xE2\x85\xAE\xE2" "\x85\xAF\xE2\x86\x83\xE2\x92\xB6\xE2\x92\xB7\xE2\x92\xB8\xE2\x92\xB9\xE2\x92\xBA\xE2\x92\xBB\xE2\x92" "\xBC\xE2\x92\xBD\xE2\x92\xBE\xE2\x92\xBF\xE2\x93\x80\xE2\x93\x81\xE2\x93\x82\xE2\x93\x83\xE2\x93\x84" "\xE2\x93\x85\xE2\x93\x86\xE2\x93\x87\xE2\x93\x88\xE2\x93\x89\xE2\x93\x8A\xE2\x93\x8B\xE2\x93\x8C\xE2" "\x93\x8D\xE2\x93\x8E\xE2\x93\x8F\xE2\xB0\x80\xE2\xB0\x81\xE2\xB0\x82\xE2\xB0\x83\xE2\xB0\x84\xE2\xB0" "\x85\xE2\xB0\x86\xE2\xB0\x87\xE2\xB0\x88\xE2\xB0\x89\xE2\xB0\x8A\xE2\xB0\x8B\xE2\xB0\x8C\xE2\xB0\x8D" "\xE2\xB0\x8E\xE2\xB0\x8F\xE2\xB0\x90\xE2\xB0\x91\xE2\xB0\x92\xE2\xB0\x93\xE2\xB0\x94\xE2\xB0\x95\xE2" "\xB0\x96\xE2\xB0\x97\xE2\xB0\x98\xE2\xB0\x99\xE2\xB0\x9A\xE2\xB0\x9B\xE2\xB0\x9C\xE2\xB0\x9D\xE2\xB0" "\x9E\xE2\xB0\x9F\xE2\xB0\xA0\xE2\xB0\xA1\xE2\xB0\xA2\xE2\xB0\xA3\xE2\xB0\xA4\xE2\xB0\xA5\xE2\xB0\xA6" "\xE2\xB0\xA7\xE2\xB0\xA8\xE2\xB0\xA9\xE2\xB0\xAA\xE2\xB0\xAB\xE2\xB0\xAC\xE2\xB0\xAD\xE2\xB0\xAE\xE2" "\xB1\xA0\xC8\xBA\xC8\xBE\xE2\xB1\xA7\xE2\xB1\xA9\xE2\xB1\xAB\xE2\xB1\xB2\xE2\xB1\xB5\xE2\xB2\x80\xE2" "\xB2\x82\xE2\xB2\x84\xE2\xB2\x86\xE2\xB2\x88\xE2\xB2\x8A\xE2\xB2\x8C\xE2\xB2\x8E\xE2\xB2\x90\xE2\xB2" "\x92\xE2\xB2\x94\xE2\xB2\x96\xE2\xB2\x98\xE2\xB2\x9A\xE2\xB2\x9C\xE2\xB2\x9E\xE2\xB2\xA0\xE2\xB2\xA2" "\xE2\xB2\xA4\xE2\xB2\xA6\xE2\xB2\xA8\xE2\xB2\xAA\xE2\xB2\xAC\xE2\xB2\xAE\xE2\xB2\xB0\xE2\xB2\xB2\xE2" "\xB2\xB4\xE2\xB2\xB6\xE2\xB2\xB8\xE2\xB2\xBA\xE2\xB2\xBC\xE2\xB2\xBE\xE2\xB3\x80\xE2\xB3\x82\xE2\xB3" "\x84\xE2\xB3\x86\xE2\xB3\x88\xE2\xB3\x8A\xE2\xB3\x8C\xE2\xB3\x8E\xE2\xB3\x90\xE2\xB3\x92\xE2\xB3\x94" "\xE2\xB3\x96\xE2\xB3\x98\xE2\xB3\x9A\xE2\xB3\x9C\xE2\xB3\x9E\xE2\xB3\xA0\xE2\xB3\xA2\xE2\xB3\xAB\xE2" "\xB3\xAD\xE2\xB3\xB2\xE1\x82\xA0\xE1\x82\xA1\xE1\x82\xA2\xE1\x82\xA3\xE1\x82\xA4\xE1\x82\xA5\xE1\x82" "\xA6\xE1\x82\xA7\xE1\x82\xA8\xE1\x82\xA9\xE1\x82\xAA\xE1\x82\xAB\xE1\x82\xAC\xE1\x82\xAD\xE1\x82\xAE" "\xE1\x82\xAF\xE1\x82\xB0\xE1\x82\xB1\xE1\x82\xB2\xE1\x82\xB3\xE1\x82\xB4\xE1\x82\xB5\xE1\x82\xB6\xE1" "\x82\xB7\xE1\x82\xB8\xE1\x82\xB9\xE1\x82\xBA\xE1\x82\xBB\xE1\x82\xBC\xE1\x82\xBD\xE1\x82\xBE\xE1\x82" "\xBF\xE1\x83\x80\xE1\x83\x81\xE1\x83\x82\xE1\x83\x83\xE1\x83\x84\xE1\x83\x85\xE1\x83\x87\xE1\x83\x8D" "\xEA\x99\x80\xEA\x99\x82\xEA\x99\x84\xEA\x99\x86\xEA\x99\x88\xEA\x99\x8A\xEA\x99\x8C\xEA\x99\x8E\xEA" "\x99\x90\xEA\x99\x92\xEA\x99\x94\xEA\x99\x96\xEA\x99\x98\xEA\x99\x9A\xEA\x99\x9C\xEA\x99\x9E\xEA\x99" "\xA0\xEA\x99\xA2\xEA\x99\xA4\xEA\x99\xA6\xEA\x99\xA8\xEA\x99\xAA\xEA\x99\xAC\xEA\x9A\x80\xEA\x9A\x82" "\xEA\x9A\x84\xEA\x9A\x86\xEA\x9A\x88\xEA\x9A\x8A\xEA\x9A\x8C\xEA\x9A\x8E\xEA\x9A\x90\xEA\x9A\x92\xEA" "\x9A\x94\xEA\x9A\x96\xEA\x9A\x98\xEA\x9A\x9A\xEA\x9C\xA2\xEA\x9C\xA4\xEA\x9C\xA6\xEA\x9C\xA8\xEA\x9C" "\xAA\xEA\x9C\xAC\xEA\x9C\xAE\xEA\x9C\xB2\xEA\x9C\xB4\xEA\x9C\xB6\xEA\x9C\xB8\xEA\x9C\xBA\xEA\x9C\xBC" "\xEA\x9C\xBE\xEA\x9D\x80\xEA\x9D\x82\xEA\x9D\x84\xEA\x9D\x86\xEA\x9D\x88\xEA\x9D\x8A\xEA\x9D\x8C\xEA" "\x9D\x8E\xEA\x9D\x90\xEA\x9D\x92\xEA\x9D\x94\xEA\x9D\x96\xEA\x9D\x98\xEA\x9D\x9A\xEA\x9D\x9C\xEA\x9D" "\x9E\xEA\x9D\xA0\xEA\x9D\xA2\xEA\x9D\xA4\xEA\x9D\xA6\xEA\x9D\xA8\xEA\x9D\xAA\xEA\x9D\xAC\xEA\x9D\xAE" "\xEA\x9D\xB9\xEA\x9D\xBB\xEA\x9D\xBE\xEA\x9E\x80\xEA\x9E\x82\xEA\x9E\x84\xEA\x9E\x86\xEA\x9E\x8B\xEA" "\x9E\x90\xEA\x9E\x92\xEA\x9E\x96\xEA\x9E\x98\xEA\x9E\x9A\xEA\x9E\x9C\xEA\x9E\x9E\xEA\x9E\xA0\xEA\x9E" "\xA2\xEA\x9E\xA4\xEA\x9E\xA6\xEA\x9E\xA8\x46\x46\x46\x49\x46\x4C\x46\x46\x49\x46\x46\x4C\x53\x54\xD5" "\x84\xD5\x86\xD5\x84\xD4\xB5\xD5\x84\xD4\xBB\xD5\x8E\xD5\x86\xD5\x84\xD4\xBD\xEF\xBC\xA1\xEF\xBC\xA2" "\xEF\xBC\xA3\xEF\xBC\xA4\xEF\xBC\xA5\xEF\xBC\xA6\xEF\xBC\xA7\xEF\xBC\xA8\xEF\xBC\xA9\xEF\xBC\xAA\xEF" "\xBC\xAB\xEF\xBC\xAC\xEF\xBC\xAD\xEF\xBC\xAE\xEF\xBC\xAF\xEF\xBC\xB0\xEF\xBC\xB1\xEF\xBC\xB2\xEF\xBC" "\xB3\xEF\xBC\xB4\xEF\xBC\xB5\xEF\xBC\xB6\xEF\xBC\xB7\xEF\xBC\xB8\xEF\xBC\xB9\xEF\xBC\xBA\xF0\x90\x90" "\x80\xF0\x90\x90\x81\xF0\x90\x90\x82\xF0\x90\x90\x83\xF0\x90\x90\x84\xF0\x90\x90\x85\xF0\x90\x90\x86" "\xF0\x90\x90\x87\xF0\x90\x90\x88\xF0\x90\x90\x89\xF0\x90\x90\x8A\xF0\x90\x90\x8B\xF0\x90\x90\x8C\xF0" "\x90\x90\x8D\xF0\x90\x90\x8E\xF0\x90\x90\x8F\xF0\x90\x90\x90\xF0\x90\x90\x91\xF0\x90\x90\x92\xF0\x90" "\x90\x93\xF0\x90\x90\x94\xF0\x90\x90\x95\xF0\x90\x90\x96\xF0\x90\x90\x97\xF0\x90\x90\x98\xF0\x90\x90" "\x99\xF0\x90\x90\x9A\xF0\x90\x90\x9B\xF0\x90\x90\x9C\xF0\x90\x90\x9D\xF0\x90\x90\x9E\xF0\x90\x90\x9F" "\xF0\x90\x90\xA0\xF0\x90\x90\xA1\xF0\x90\x90\xA2\xF0\x90\x90\xA3\xF0\x90\x90\xA4\xF0\x90\x90\xA5\xF0" "\x90\x90\xA6\xF0\x90\x90\xA7\xF0\x91\xA2\xA0\xF0\x91\xA2\xA1\xF0\x91\xA2\xA2\xF0\x91\xA2\xA3\xF0\x91" "\xA2\xA4\xF0\x91\xA2\xA5\xF0\x91\xA2\xA6\xF0\x91\xA2\xA7\xF0\x91\xA2\xA8\xF0\x91\xA2\xA9\xF0\x91\xA2" "\xAA\xF0\x91\xA2\xAB\xF0\x91\xA2\xAC\xF0\x91\xA2\xAD\xF0\x91\xA2\xAE\xF0\x91\xA2\xAF\xF0\x91\xA2\xB0" "\xF0\x91\xA2\xB1\xF0\x91\xA2\xB2\xF0\x91\xA2\xB3\xF0\x91\xA2\xB4\xF0\x91\xA2\xB5\xF0\x91\xA2\xB6\xF0" "\x91\xA2\xB7\xF0\x91\xA2\xB8\xF0\x91\xA2\xB9\xF0\x91\xA2\xBA\xF0\x91\xA2\xBB\xF0\x91\xA2\xBC\xF0\x91" "\xA2\xBD\xF0\x91\xA2\xBE\xF0\x91\xA2\xBF\xC3\xA0\xC3\xA1\xC3\xA2\xC3\xA3\xC3\xA4\xC3\xA5\xC3\xA7\xC3" "\xA8\xC3\xA9\xC3\xAA\xC3\xAB\xC3\xAC\xC3\xAD\xC3\xAE\xC3\xAF\xC3\xB1\xC3\xB2\xC3\xB3\xC3\xB4\xC3\xB5" "\xC3\xB6\xC3\xB9\xC3\xBA\xC3\xBB\xC3\xBC\xC3\xBD\xC3\xBE\xC4\x81\xC4\x83\xC4\x85\xC4\x87\xC4\x89\xC4" "\x8B\xC4\x8D\xC4\x8F\xC4\x91\xC4\x93\xC4\x95\xC4\x97\xC4\x99\xC4\x9B\xC4\x9D\xC4\x9F\xC4\xA1\xC4\xA3" "\xC4\xA5\xC4\xA9\xC4\xAB\xC4\xAD\xC4\xAF\x69\xCC\x87\xC4\xB3\xC4\xB5\xC4\xB7\xC4\xBA\xC4\xBC\xC4\xBE" "\xC5\x80\xC5\x82\xC5\x84\xC5\x86\xC5\x88\xC5\x8D\xC5\x8F\xC5\x91\xC5\x95\xC5\x97\xC5\x99\xC5\x9B\xC5" "\x9D\xC5\x9F\xC5\xA1\xC5\xA3\xC5\xA5\xC5\xA7\xC5\xA9\xC5\xAB\xC5\xAD\xC5\xAF\xC5\xB1\xC5\xB3\xC5\xB5" "\xC5\xB7\xC3\xBF\xC5\xBA\xC5\xBC\xC5\xBE\xC9\x93\xC6\x83\xC6\x85\xC6\x88\xC9\x96\xC9\x97\xC6\x8C\xC7" "\x9D\xC6\x92\xC9\xA0\xC6\x99\xC6\xA1\xC6\xA3\xC6\xA5\xCA\x80\xC6\xA8\xC6\xAD\xCA\x88\xC6\xB0\xC6\xB4" "\xC6\xB6\xC6\xB9\xC6\xBD\xC7\x86\xC7\x89\xC7\x8C\xC7\x8E\xC7\x90\xC7\x92\xC7\x94\xC7\x96\xC7\x98\xC7" "\x9A\xC7\x9C\xC7\x9F\xC7\xA1\xC7\xA3\xC7\xA5\xC7\xA7\xC7\xA9\xC7\xAB\xC7\xAD\xC7\xAF\xC7\xB3\xC7\xB5" "\xC6\x95\xC6\xBF\xC7\xB9\xC7\xBB\xC7\xBD\xC7\xBF\xC8\x81\xC8\x83\xC8\x85\xC8\x87\xC8\x89\xC8\x8B\xC8" "\x8D\xC8\x8F\xC8\x91\xC8\x93\xC8\x95\xC8\x97\xC8\x99\xC8\x9B\xC8\x9D\xC8\x9F\xC6\x9E\xC8\xA3\xC8\xA5" "\xC8\xA7\xC8\xA9\xC8\xAB\xC8\xAD\xC8\xAF\xC8\xB1\xC8\xB3\xE2\xB1\xA5\xC8\xBC\xC6\x9A\xE2\xB1\xA6\xC9" "\x82\xC6\x80\xC9\x87\xC9\x89\xC9\x8B\xC9\x8D\xC9\x8F\xCD\xB1\xCD\xB3\xCD\xB7\xCF\xB3\xCE\xAC\xCE\xAD" "\xCE\xAE\xCE\xAF\xCF\x8C\xCF\x8D\xCF\x8E\xCF\x8A\xCF\x8B\xCF\x97\xCF\x99\xCF\x9B\xCF\x9F\xCF\xA1\xCF" "\xA3\xCF\xA5\xCF\xA7\xCF\xA9\xCF\xAB\xCF\xAD\xCF\xAF\xCF\xB8\xCF\xB2\xCF\xBB\xCD\xBB\xCD\xBC\xCD\xBD" "\xD1\x90\xD1\x91\xD1\x92\xD1\x93\xD1\x94\xD1\x95\xD1\x97\xD1\x98\xD1\x99\xD1\x9A\xD1\x9B\xD1\x9C\xD1" "\x9D\xD1\x9E\xD1\x9F\xD0\xB1\xD0\xB2\xD0\xB4\xD0\xB9\xD0\xBB\xD0\xBC\xD0\xBF\xD1\x80\xD1\x81\xD1\x82" "\xD1\x84\xD1\x85\xD1\x86\xD1\x88\xD1\x89\xD1\x8E\xD1\x8F\xD1\xA1\xD1\xA3\xD1\xA5\xD1\xA7\xD1\xA9\xD1" "\xAB\xD1\xAD\xD1\xAF\xD1\xB1\xD1\xB3\xD1\xB7\xD1\xB9\xD1\xBB\xD1\xBD\xD1\xBF\xD2\x81\xD2\x8B\xD2\x8D" "\xD2\x8F\xD2\x91\xD2\x93\xD2\x95\xD2\x97\xD2\x99\xD2\x9B\xD2\x9D\xD2\x9F\xD2\xA1\xD2\xA3\xD2\xA5\xD2" "\xA7\xD2\xA9\xD2\xAB\xD2\xAD\xD2\xAF\xD2\xB1\xD2\xB3\xD2\xB5\xD2\xB7\xD2\xB9\xD2\xBB\xD2\xBD\xD2\xBF" "\xD3\x8F\xD3\x82\xD3\x84\xD3\x86\xD3\x88\xD3\x8A\xD3\x8C\xD3\x8E\xD3\x91\xD3\x93\xD3\x95\xD3\x97\xD3" "\x9B\xD3\x9D\xD3\x9F\xD3\xA1\xD3\xA3\xD3\xA5\xD3\xA7\xD3\xAB\xD3\xAD\xD3\xAF\xD3\xB1\xD3\xB3\xD3\xB5" "\xD3\xB7\xD3\xB9\xD3\xBB\xD3\xBD\xD3\xBF\xD4\x81\xD4\x83\xD4\x85\xD4\x87\xD4\x89\xD4\x8B\xD4\x8D\xD4" "\x8F\xD4\x91\xD4\x93\xD4\x95\xD4\x97\xD4\x99\xD4\x9B\xD4\x9D\xD4\x9F\xD4\xA1\xD4\xA3\xD4\xA5\xD4\xA7" "\xD4\xA9\xD4\xAB\xD4\xAD\xD4\xAF\xD5\xA1\xD5\xA2\xD5\xA3\xD5\xA4\xD5\xA6\xD5\xA7\xD5\xA8\xD5\xA9\xD5" "\xAA\xD5\xAC\xD5\xAE\xD5\xAF\xD5\xB0\xD5\xB1\xD5\xB2\xD5\xB3\xD5\xB5\xD5\xB7\xD5\xB8\xD5\xB9\xD5\xBA" "\xD5\xBB\xD5\xBC\xD5\xBD\xD5\xBF\xD6\x80\xD6\x81\xD6\x83\xD6\x84\xD6\x85\xD6\x86\xE2\xB4\x80\xE2\xB4" "\x81\xE2\xB4\x82\xE2\xB4\x83\xE2\xB4\x84\xE2\xB4\x85\xE2\xB4\x86\xE2\xB4\x87\xE2\xB4\x88\xE2\xB4\x89" "\xE2\xB4\x8A\xE2\xB4\x8B\xE2\xB4\x8C\xE2\xB4\x8D\xE2\xB4\x8E\xE2\xB4\x8F\xE2\xB4\x90\xE2\xB4\x91\xE2" "\xB4\x92\xE2\xB4\x93\xE2\xB4\x94\xE2\xB4\x95\xE2\xB4\x96\xE2\xB4\x97\xE2\xB4\x98\xE2\xB4\x99\xE2\xB4" "\x9A\xE2\xB4\x9B\xE2\xB4\x9C\xE2\xB4\x9D\xE2\xB4\x9E\xE2\xB4\x9F\xE2\xB4\xA0\xE2\xB4\xA1\xE2\xB4\xA2" "\xE2\xB4\xA3\xE2\xB4\xA4\xE2\xB4\xA5\xE2\xB4\xA7\xE2\xB4\xAD\xE1\xB8\x81\xE1\xB8\x83\xE1\xB8\x85\xE1" "\xB8\x87\xE1\xB8\x89\xE1\xB8\x8B\xE1\xB8\x8D\xE1\xB8\x8F\xE1\xB8\x91\xE1\xB8\x93\xE1\xB8\x95\xE1\xB8" "\x97\xE1\xB8\x99\xE1\xB8\x9B\xE1\xB8\x9D\xE1\xB8\x9F\xE1\xB8\xA1\xE1\xB8\xA3\xE1\xB8\xA5\xE1\xB8\xA7" "\xE1\xB8\xA9\xE1\xB8\xAB\xE1\xB8\xAD\xE1\xB8\xAF\xE1\xB8\xB1\xE1\xB8\xB3\xE1\xB8\xB5\xE1\xB8\xB7\xE1" "\xB8\xB9\xE1\xB8\xBB\xE1\xB8\xBD\xE1\xB8\xBF\xE1\xB9\x81\xE1\xB9\x83\xE1\xB9\x85\xE1\xB9\x87\xE1\xB9" "\x89\xE1\xB9\x8B\xE1\xB9\x8D\xE1\xB9\x8F\xE1\xB9\x91\xE1\xB9\x93\xE1\xB9\x95\xE1\xB9\x97\xE1\xB9\x99" "\xE1\xB9\x9B\xE1\xB9\x9D\xE1\xB9\x9F\xE1\xB9\xA1\xE1\xB9\xA3\xE1\xB9\xA5\xE1\xB9\xA7\xE1\xB9\xA9\xE1" "\xB9\xAB\xE1\xB9\xAD\xE1\xB9\xAF\xE1\xB9\xB1\xE1\xB9\xB3\xE1\xB9\xB5\xE1\xB9\xB7\xE1\xB9\xB9\xE1\xB9" "\xBB\xE1\xB9\xBD\xE1\xB9\xBF\xE1\xBA\x81\xE1\xBA\x83\xE1\xBA\x85\xE1\xBA\x87\xE1\xBA\x89\xE1\xBA\x8B" "\xE1\xBA\x8D\xE1\xBA\x8F\xE1\xBA\x91\xE1\xBA\x93\xE1\xBA\x95\xC3\x9F\xE1\xBA\xA1\xE1\xBA\xA3\xE1\xBA" "\xA5\xE1\xBA\xA7\xE1\xBA\xA9\xE1\xBA\xAB\xE1\xBA\xAD\xE1\xBA\xAF\xE1\xBA\xB1\xE1\xBA\xB3\xE1\xBA\xB5" "\xE1\xBA\xB7\xE1\xBA\xB9\xE1\xBA\xBB\xE1\xBA\xBD\xE1\xBA\xBF\xE1\xBB\x81\xE1\xBB\x83\xE1\xBB\x85\xE1" "\xBB\x87\xE1\xBB\x89\xE1\xBB\x8B\xE1\xBB\x8D\xE1\xBB\x8F\xE1\xBB\x91\xE1\xBB\x93\xE1\xBB\x95\xE1\xBB" "\x97\xE1\xBB\x99\xE1\xBB\x9B\xE1\xBB\x9D\xE1\xBB\x9F\xE1\xBB\xA1\xE1\xBB\xA3\xE1\xBB\xA5\xE1\xBB\xA7" "\xE1\xBB\xA9\xE1\xBB\xAB\xE1\xBB\xAD\xE1\xBB\xAF\xE1\xBB\xB1\xE1\xBB\xB3\xE1\xBB\xB5\xE1\xBB\xB7\xE1" "\xBB\xB9\xE1\xBB\xBB\xE1\xBB\xBD\xE1\xBB\xBF\xE1\xBC\x80\xE1\xBC\x81\xE1\xBC\x82\xE1\xBC\x83\xE1\xBC" "\x84\xE1\xBC\x85\xE1\xBC\x86\xE1\xBC\x87\xE1\xBC\x90\xE1\xBC\x91\xE1\xBC\x92\xE1\xBC\x93\xE1\xBC\x94" "\xE1\xBC\x95\xE1\xBC\xA0\xE1\xBC\xA1\xE1\xBC\xA2\xE1\xBC\xA3\xE1\xBC\xA4\xE1\xBC\xA5\xE1\xBC\xA6\xE1" "\xBC\xA7\xE1\xBC\xB0\xE1\xBC\xB1\xE1\xBC\xB2\xE1\xBC\xB3\xE1\xBC\xB4\xE1\xBC\xB5\xE1\xBC\xB6\xE1\xBC" "\xB7\xE1\xBD\x80\xE1\xBD\x81\xE1\xBD\x82\xE1\xBD\x83\xE1\xBD\x84\xE1\xBD\x85\xE1\xBD\x91\xE1\xBD\x93" "\xE1\xBD\x95\xE1\xBD\x97\xE1\xBD\xA0\xE1\xBD\xA1\xE1\xBD\xA2\xE1\xBD\xA3\xE1\xBD\xA4\xE1\xBD\xA5\xE1" "\xBD\xA6\xE1\xBD\xA7\xE1\xBE\x80\xE1\xBE\x81\xE1\xBE\x82\xE1\xBE\x83\xE1\xBE\x84\xE1\xBE\x85\xE1\xBE" "\x86\xE1\xBE\x87\xE1\xBE\x90\xE1\xBE\x91\xE1\xBE\x92\xE1\xBE\x93\xE1\xBE\x94\xE1\xBE\x95\xE1\xBE\x96" "\xE1\xBE\x97\xE1\xBE\xA0\xE1\xBE\xA1\xE1\xBE\xA2\xE1\xBE\xA3\xE1\xBE\xA4\xE1\xBE\xA5\xE1\xBE\xA6\xE1" "\xBE\xA7\xE1\xBE\xB0\xE1\xBE\xB1\xE1\xBD\xB0\xE1\xBD\xB1\xE1\xBE\xB3\xE1\xBD\xB2\xE1\xBD\xB3\xE1\xBD" "\xB4\xE1\xBD\xB5\xE1\xBF\x83\xE1\xBF\x90\xE1\xBF\x91\xE1\xBD\xB6\xE1\xBD\xB7\xE1\xBF\xA0\xE1\xBF\xA1" "\xE1\xBD\xBA\xE1\xBD\xBB\xE1\xBF\xA5\xE1\xBD\xB8\xE1\xBD\xB9\xE1\xBD\xBC\xE1\xBD\xBD\xE1\xBF\xB3\xE2" "\x85\x8E\xE2\x85\xB0\xE2\x85\xB1\xE2\x85\xB2\xE2\x85\xB3\xE2\x85\xB4\xE2\x85\xB5\xE2\x85\xB6\xE2\x85" "\xB7\xE2\x85\xB8\xE2\x85\xB9\xE2\x85\xBA\xE2\x85\xBB\xE2\x85\xBC\xE2\x85\xBD\xE2\x85\xBE\xE2\x85\xBF" "\xE2\x86\x84\xE2\x93\x90\xE2\x93\x91\xE2\x93\x92\xE2\x93\x93\xE2\x93\x94\xE2\x93\x95\xE2\x93\x96\xE2" "\x93\x97\xE2\x93\x98\xE2\x93\x99\xE2\x93\x9A\xE2\x93\x9B\xE2\x93\x9C\xE2\x93\x9D\xE2\x93\x9E\xE2\x93" "\x9F\xE2\x93\xA0\xE2\x93\xA1\xE2\x93\xA2\xE2\x93\xA3\xE2\x93\xA4\xE2\x93\xA5\xE2\x93\xA6\xE2\x93\xA7" "\xE2\x93\xA8\xE2\x93\xA9\xE2\xB0\xB0\xE2\xB0\xB1\xE2\xB0\xB2\xE2\xB0\xB3\xE2\xB0\xB4\xE2\xB0\xB5\xE2" "\xB0\xB6\xE2\xB0\xB7\xE2\xB0\xB8\xE2\xB0\xB9\xE2\xB0\xBA\xE2\xB0\xBB\xE2\xB0\xBC\xE2\xB0\xBD\xE2\xB0" "\xBE\xE2\xB0\xBF\xE2\xB1\x80\xE2\xB1\x81\xE2\xB1\x82\xE2\xB1\x83\xE2\xB1\x84\xE2\xB1\x85\xE2\xB1\x86" "\xE2\xB1\x87\xE2\xB1\x88\xE2\xB1\x89\xE2\xB1\x8A\xE2\xB1\x8B\xE2\xB1\x8C\xE2\xB1\x8D\xE2\xB1\x8E\xE2" "\xB1\x8F\xE2\xB1\x90\xE2\xB1\x91\xE2\xB1\x92\xE2\xB1\x93\xE2\xB1\x94\xE2\xB1\x95\xE2\xB1\x96\xE2\xB1" "\x97\xE2\xB1\x98\xE2\xB1\x99\xE2\xB1\x9A\xE2\xB1\x9B\xE2\xB1\x9C\xE2\xB1\x9D\xE2\xB1\x9E\xE2\xB1\xA1" "\xE1\xB5\xBD\xC9\xBD\xE2\xB1\xA8\xE2\xB1\xAA\xE2\xB1\xAC\xE2\xB1\xB3\xE2\xB1\xB6\xC8\xBF\xC9\x80\xE2" "\xB2\x81\xE2\xB2\x83\xE2\xB2\x85\xE2\xB2\x87\xE2\xB2\x89\xE2\xB2\x8B\xE2\xB2\x8D\xE2\xB2\x8F\xE2\xB2" "\x91\xE2\xB2\x93\xE2\xB2\x95\xE2\xB2\x97\xE2\xB2\x99\xE2\xB2\x9B\xE2\xB2\x9D\xE2\xB2\x9F\xE2\xB2\xA1" "\xE2\xB2\xA3\xE2\xB2\xA5\xE2\xB2\xA7\xE2\xB2\xA9\xE2\xB2\xAB\xE2\xB2\xAD\xE2\xB2\xAF\xE2\xB2\xB1\xE2" "\xB2\xB3\xE2\xB2\xB5\xE2\xB2\xB7\xE2\xB2\xB9\xE2\xB2\xBB\xE2\xB2\xBD\xE2\xB2\xBF\xE2\xB3\x81\xE2\xB3" "\x83\xE2\xB3\x85\xE2\xB3\x87\xE2\xB3\x89\xE2\xB3\x8B\xE2\xB3\x8D\xE2\xB3\x8F\xE2\xB3\x91\xE2\xB3\x93" "\xE2\xB3\x95\xE2\xB3\x97\xE2\xB3\x99\xE2\xB3\x9B\xE2\xB3\x9D\xE2\xB3\x9F\xE2\xB3\xA1\xE2\xB3\xA3\xE2" "\xB3\xAC\xE2\xB3\xAE\xE2\xB3\xB3\xEA\x99\x81\xEA\x99\x83\xEA\x99\x85\xEA\x99\x87\xEA\x99\x89\xEA\x99" "\x8B\xEA\x99\x8D\xEA\x99\x8F\xEA\x99\x91\xEA\x99\x93\xEA\x99\x95\xEA\x99\x97\xEA\x99\x99\xEA\x99\x9B" "\xEA\x99\x9D\xEA\x99\x9F\xEA\x99\xA1\xEA\x99\xA3\xEA\x99\xA5\xEA\x99\xA7\xEA\x99\xA9\xEA\x99\xAB\xEA" "\x99\xAD\xEA\x9A\x81\xEA\x9A\x83\xEA\x9A\x85\xEA\x9A\x87\xEA\x9A\x89\xEA\x9A\x8B\xEA\x9A\x8D\xEA\x9A" "\x8F\xEA\x9A\x91\xEA\x9A\x93\xEA\x9A\x95\xEA\x9A\x97\xEA\x9A\x99\xEA\x9A\x9B\xEA\x9C\xA3\xEA\x9C\xA5" "\xEA\x9C\xA9\xEA\x9C\xAB\xEA\x9C\xAD\xEA\x9C\xAF\xEA\x9C\xB3\xEA\x9C\xB5\xEA\x9C\xB7\xEA\x9C\xB9\xEA" "\x9C\xBB\xEA\x9C\xBD\xEA\x9C\xBF\xEA\x9D\x81\xEA\x9D\x83\xEA\x9D\x85\xEA\x9D\x87\xEA\x9D\x89\xEA\x9D" "\x8B\xEA\x9D\x8D\xEA\x9D\x8F\xEA\x9D\x91\xEA\x9D\x93\xEA\x9D\x95\xEA\x9D\x97\xEA\x9D\x99\xEA\x9D\x9B" "\xEA\x9D\x9D\xEA\x9D\x9F\xEA\x9D\xA1\xEA\x9D\xA3\xEA\x9D\xA5\xEA\x9D\xA7\xEA\x9D\xA9\xEA\x9D\xAB\xEA" "\x9D\xAD\xEA\x9D\xBA\xEA\x9D\xBC\xE1\xB5\xB9\xEA\x9D\xBF\xEA\x9E\x81\xEA\x9E\x83\xEA\x9E\x85\xEA\x9E" "\x87\xEA\x9E\x8C\xEA\x9E\x91\xEA\x9E\x93\xEA\x9E\x97\xEA\x9E\x99\xEA\x9E\x9B\xEA\x9E\x9D\xEA\x9E\x9F" "\xEA\x9E\xA1\xEA\x9E\xA3\xEA\x9E\xA5\xEA\x9E\xA7\xEA\x9E\xA9\xC9\xAC\xCA\x9E\xCA\x87\xEF\xBD\x81\xEF" "\xBD\x82\xEF\xBD\x83\xEF\xBD\x84\xEF\xBD\x85\xEF\xBD\x86\xEF\xBD\x87\xEF\xBD\x88\xEF\xBD\x89\xEF\xBD" "\x8A\xEF\xBD\x8B\xEF\xBD\x8C\xEF\xBD\x8D\xEF\xBD\x8E\xEF\xBD\x8F\xEF\xBD\x90\xEF\xBD\x91\xEF\xBD\x92" "\xEF\xBD\x93\xEF\xBD\x94\xEF\xBD\x95\xEF\xBD\x96\xEF\xBD\x97\xEF\xBD\x98\xEF\xBD\x99\xEF\xBD\x9A\xF0" "\x90\x90\xA8\xF0\x90\x90\xA9\xF0\x90\x90\xAA\xF0\x90\x90\xAB\xF0\x90\x90\xAC\xF0\x90\x90\xAD\xF0\x90" "\x90\xAE\xF0\x90\x90\xAF\xF0\x90\x90\xB0\xF0\x90\x90\xB1\xF0\x90\x90\xB2\xF0\x90\x90\xB3\xF0\x90\x90" "\xB4\xF0\x90\x90\xB5\xF0\x90\x90\xB6\xF0\x90\x90\xB7\xF0\x90\x90\xB8\xF0\x90\x90\xB9\xF0\x90\x90\xBA" "\xF0\x90\x90\xBB\xF0\x90\x90\xBC\xF0\x90\x90\xBD\xF0\x90\x90\xBE\xF0\x90\x90\xBF\xF0\x90\x91\x80\xF0" "\x90\x91\x81\xF0\x90\x91\x82\xF0\x90\x91\x83\xF0\x90\x91\x84\xF0\x90\x91\x85\xF0\x90\x91\x86\xF0\x90" "\x91\x87\xF0\x90\x91\x88\xF0\x90\x91\x89\xF0\x90\x91\x8A\xF0\x90\x91\x8B\xF0\x90\x91\x8C\xF0\x90\x91" "\x8D\xF0\x90\x91\x8E\xF0\x90\x91\x8F\xF0\x91\xA3\x80\xF0\x91\xA3\x81\xF0\x91\xA3\x82\xF0\x91\xA3\x83" "\xF0\x91\xA3\x84\xF0\x91\xA3\x85\xF0\x91\xA3\x86\xF0\x91\xA3\x87\xF0\x91\xA3\x88\xF0\x91\xA3\x89\xF0" "\x91\xA3\x8A\xF0\x91\xA3\x8B\xF0\x91\xA3\x8C\xF0\x91\xA3\x8D\xF0\x91\xA3\x8E\xF0\x91\xA3\x8F\xF0\x91" "\xA3\x90\xF0\x91\xA3\x91\xF0\x91\xA3\x92\xF0\x91\xA3\x93\xF0\x91\xA3\x94\xF0\x91\xA3\x95\xF0\x91\xA3" "\x96\xF0\x91\xA3\x97\xF0\x91\xA3\x98\xF0\x91\xA3\x99\xF0\x91\xA3\x9A\xF0\x91\xA3\x9B\xF0\x91\xA3\x9C" "\xF0\x91\xA3\x9D\xF0\x91\xA3\x9E\xF0\x91\xA3\x9F\x53\x73\xC7\x85\xC7\x88\xC7\x8B\xC7\xB2\xD4\xB5\xD6" "\x82\xE1\xBE\x88\xE1\xBE\x89\xE1\xBE\x8A\xE1\xBE\x8B\xE1\xBE\x8C\xE1\xBE\x8D\xE1\xBE\x8E\xE1\xBE\x8F" "\xE1\xBE\x98\xE1\xBE\x99\xE1\xBE\x9A\xE1\xBE\x9B\xE1\xBE\x9C\xE1\xBE\x9D\xE1\xBE\x9E\xE1\xBE\x9F\xE1" "\xBE\xA8\xE1\xBE\xA9\xE1\xBE\xAA\xE1\xBE\xAB\xE1\xBE\xAC\xE1\xBE\xAD\xE1\xBE\xAE\xE1\xBE\xAF\xE1\xBE" "\xBA\xCD\x85\xE1\xBE\xBC\xCE\x86\xCD\x85\xCE\x91\xCD\x82\xCD\x85\xE1\xBF\x8A\xCD\x85\xE1\xBF\x8C\xCE" "\x89\xCD\x85\xCE\x97\xCD\x82\xCD\x85\xE1\xBF\xBA\xCD\x85\xE1\xBF\xBC\xCE\x8F\xCD\x85\xCE\xA9\xCD\x82" "\xCD\x85\x46\x66\x46\x69\x46\x6C\x46\x66\x69\x46\x66\x6C\x53\x74\xD5\x84\xD5\xB6\xD5\x84\xD5\xA5\xD5" "\x84\xD5\xAB\xD5\x8E\xD5\xB6\xD5\x84\xD5\xAD\x73\x73\xE1\xBC\x80\xCE\xB9\xE1\xBC\x81\xCE\xB9\xE1\xBC" "\x82\xCE\xB9\xE1\xBC\x83\xCE\xB9\xE1\xBC\x84\xCE\xB9\xE1\xBC\x85\xCE\xB9\xE1\xBC\x86\xCE\xB9\xE1\xBC" "\x87\xCE\xB9\xE1\xBC\xA0\xCE\xB9\xE1\xBC\xA1\xCE\xB9\xE1\xBC\xA2\xCE\xB9\xE1\xBC\xA3\xCE\xB9\xE1\xBC" "\xA4\xCE\xB9\xE1\xBC\xA5\xCE\xB9\xE1\xBC\xA6\xCE\xB9\xE1\xBC\xA7\xCE\xB9\xE1\xBD\xA0\xCE\xB9\xE1\xBD" "\xA1\xCE\xB9\xE1\xBD\xA2\xCE\xB9\xE1\xBD\xA3\xCE\xB9\xE1\xBD\xA4\xCE\xB9\xE1\xBD\xA5\xCE\xB9\xE1\xBD" "\xA6\xCE\xB9\xE1\xBD\xA7\xCE\xB9\xE1\xBD\xB0\xCE\xB9\xCE\xB1\xCE\xB9\xCE\xAC\xCE\xB9\xCE\xB1\xCD\x82" "\xCE\xB9\xE1\xBD\xB4\xCE\xB9\xCE\xB7\xCE\xB9\xCE\xAE\xCE\xB9\xCE\xB7\xCD\x82\xCE\xB9\xE1\xBD\xBC\xCE" "\xB9\xCF\x89\xCE\xB9\xCF\x8E\xCE\xB9\xCF\x89\xCD\x82\xCE\xB9" ; const size_t CompressedStringDataLength = 19415; ================================================ FILE: external/utf8rewind/source/unicodedatabase.h ================================================ /* Copyright (C) 2014-2016 Quinten Lansu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _UTF8REWIND_UNICODEDATABASE_H_ #define _UTF8REWIND_UNICODEDATABASE_H_ /*! \file \brief Unicode property database. \cond INTERNAL */ #include "../include/utf8rewind/utf8rewind.h" typedef struct { unicode_t codepoint; uint32_t length_and_offset; } DecompositionRecord; typedef struct { uint64_t key; unicode_t value; } CompositionRecord; extern const size_t* GeneralCategoryIndexPtr; extern const uint32_t* GeneralCategoryDataPtr; extern const size_t* CanonicalCombiningClassIndexPtr; extern const uint8_t* CanonicalCombiningClassDataPtr; extern const size_t* QuickCheckCaseMappedIndexPtr; extern const uint8_t* QuickCheckCaseMappedDataPtr; extern const size_t* QuickCheckNFCIndexPtr; extern const uint8_t* QuickCheckNFCDataPtr; extern const size_t* QuickCheckNFDIndexPtr; extern const uint8_t* QuickCheckNFDDataPtr; extern const size_t* QuickCheckNFKCIndexPtr; extern const uint8_t* QuickCheckNFKCDataPtr; extern const size_t* QuickCheckNFKDIndexPtr; extern const uint8_t* QuickCheckNFKDDataPtr; extern const size_t UnicodeNFDRecordCount; extern const DecompositionRecord* UnicodeNFDRecordPtr; extern const size_t UnicodeNFKDRecordCount; extern const DecompositionRecord* UnicodeNFKDRecordPtr; extern const size_t UnicodeUppercaseRecordCount; extern const DecompositionRecord* UnicodeUppercaseRecordPtr; extern const size_t UnicodeLowercaseRecordCount; extern const DecompositionRecord* UnicodeLowercaseRecordPtr; extern const size_t UnicodeTitlecaseRecordCount; extern const DecompositionRecord* UnicodeTitlecaseRecordPtr; extern const size_t UnicodeCompositionRecordCount; extern const CompositionRecord* UnicodeCompositionRecordPtr; extern const uint32_t* NFDIndex1Ptr; extern const uint32_t* NFDIndex2Ptr; extern const uint32_t* NFDDataPtr; extern const uint32_t* NFKDIndex1Ptr; extern const uint32_t* NFKDIndex2Ptr; extern const uint32_t* NFKDDataPtr; extern const uint32_t* UppercaseIndex1Ptr; extern const uint32_t* UppercaseIndex2Ptr; extern const uint32_t* UppercaseDataPtr; extern const uint32_t* LowercaseIndex1Ptr; extern const uint32_t* LowercaseIndex2Ptr; extern const uint32_t* LowercaseDataPtr; extern const uint32_t* TitlecaseIndex1Ptr; extern const uint32_t* TitlecaseIndex2Ptr; extern const uint32_t* TitlecaseDataPtr; extern const uint32_t* CaseFoldingIndex1Ptr; extern const uint32_t* CaseFoldingIndex2Ptr; extern const uint32_t* CaseFoldingDataPtr; extern const char* CompressedStringData; extern const size_t CompressedStringDataLength; extern const char* DecompositionData; extern const size_t DecompositionDataLength; /*! \endcond */ #endif /* _UTF8REWIND_UNICODEDATABASE_H_ */ ================================================ FILE: external/utf8rewind/source/utf8rewind.c ================================================ /* Copyright (C) 2014-2016 Quinten Lansu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "../include/utf8rewind/utf8rewind.h" #include "internal/base.h" #include "internal/casemapping.h" #include "internal/codepoint.h" #include "internal/composition.h" #include "internal/decomposition.h" #include "internal/database.h" #include "internal/seeking.h" #include "internal/streaming.h" #ifndef _WIN32 #include #else int strncasecmp(const char* s1, const char* s2, size_t n) { for(; n != 0; --n) { int c1 = tolower(*((unsigned char*) s1++)); int c2 = tolower(*((unsigned char*) s2++)); if((c1 != c2) || (c1 == '\0')) { return c1 - c2; } } return 0; } #endif size_t utf8len(const char* text) { const uint8_t* src; size_t src_length; size_t length; /* Validate input */ if (text == 0 || text[0] == 0) { return 0; } length = 0; /* Determine length in codepoints */ src = (const uint8_t*)text; src_length = strlen(text); while (src_length > 0) { uint8_t src_offset = 1; /* Check if the current byte is part of a multi-byte sequence */ uint8_t codepoint_length = codepoint_decoded_length[*src]; if (codepoint_length > 1) { /* Check every byte of the sequence */ do { if (src[src_offset] < 0x80 || /* Not a continuation byte */ src[src_offset] > 0xBF) /* Start of a new sequence */ { break; } } while (++src_offset < codepoint_length); } /* Found a codepoint */ length++; /* Move cursor */ if (src_offset >= src_length) { break; } src += src_offset; src_length -= src_offset; } return length; } size_t utf16toutf8(const utf16_t* input, size_t inputSize, char* target, size_t targetSize, int32_t* errors) { const utf16_t* src; size_t src_size; char* dst; size_t dst_size; size_t bytes_written = 0; /* Validate parameters */ UTF8_VALIDATE_PARAMETERS_CHAR(utf16_t, bytes_written); UTF8_SET_ERROR(NONE); /* Setup cursors */ src = input; src_size = inputSize; dst = target; dst_size = targetSize; /* Loop over input */ while (src_size > 0) { unicode_t codepoint; uint8_t encoded_size; if (src_size < sizeof(utf16_t)) { /* Not enough data */ goto invaliddata; } codepoint = (unicode_t)*src; if (codepoint >= SURROGATE_HIGH_START && codepoint <= SURROGATE_LOW_END) { /* Decode surrogate pair */ if (codepoint > SURROGATE_HIGH_END) { /* Missing high surrogate codepoint */ codepoint = REPLACEMENT_CHARACTER; UTF8_SET_ERROR(INVALID_DATA); } else if ( src_size < 2 * sizeof(utf16_t)) { /* Not enough data */ goto invaliddata; } else { /* Read low surrogate codepoint */ if (src[1] < SURROGATE_LOW_START || src[1] > SURROGATE_LOW_END) { /* Missing low surrogate codepoint */ codepoint = REPLACEMENT_CHARACTER; UTF8_SET_ERROR(INVALID_DATA); } else { /* Decode codepoint from surrogate pair */ codepoint = (MAX_BASIC_MULTILINGUAL_PLANE + 1) + (src[1] - SURROGATE_LOW_START) + ((src[0] - SURROGATE_HIGH_START) << 10); src++; src_size -= sizeof(utf16_t); } } } encoded_size = codepoint_write(codepoint, &dst, &dst_size); if (encoded_size == 0) { UTF8_SET_ERROR(NOT_ENOUGH_SPACE); return bytes_written; } bytes_written += encoded_size; src++; src_size -= sizeof(utf16_t); } return bytes_written; invaliddata: if (dst != 0) { if (dst_size < REPLACEMENT_CHARACTER_STRING_LENGTH) { UTF8_SET_ERROR(NOT_ENOUGH_SPACE); return bytes_written; } /* Write replacement codepoint to output */ memcpy(dst, REPLACEMENT_CHARACTER_STRING, REPLACEMENT_CHARACTER_STRING_LENGTH); } UTF8_SET_ERROR(INVALID_DATA); return bytes_written + REPLACEMENT_CHARACTER_STRING_LENGTH; } size_t utf32toutf8(const unicode_t* input, size_t inputSize, char* target, size_t targetSize, int32_t* errors) { const unicode_t* src; size_t src_size; char* dst; size_t dst_size; size_t bytes_written = 0; /* Validate parameters */ UTF8_VALIDATE_PARAMETERS_CHAR(unicode_t, bytes_written); UTF8_SET_ERROR(NONE); /* Setup cursors */ src = input; src_size = inputSize; dst = target; dst_size = targetSize; /* Loop over input */ while (src_size > 0) { unicode_t codepoint; uint8_t encoded_size; if (src_size < sizeof(unicode_t)) { /* Not enough data */ goto invaliddata; } codepoint = *src; if (codepoint >= SURROGATE_HIGH_START && codepoint <= SURROGATE_LOW_END) { /* Decode surrogate pair */ if (codepoint > SURROGATE_HIGH_END) { /* Missing high surrogate codepoint */ codepoint = REPLACEMENT_CHARACTER; UTF8_SET_ERROR(INVALID_DATA); } else if ( src_size < 2 * sizeof(unicode_t)) { /* Not enough data */ goto invaliddata; } else { /* Read low surrogate codepoint */ if (src[1] < SURROGATE_LOW_START || src[1] > SURROGATE_LOW_END) { /* Missing low surrogate codepoint */ codepoint = REPLACEMENT_CHARACTER; UTF8_SET_ERROR(INVALID_DATA); } else { /* Decode codepoint from surrogate pair */ codepoint = (MAX_BASIC_MULTILINGUAL_PLANE + 1) + (src[1] - SURROGATE_LOW_START) + ((src[0] - SURROGATE_HIGH_START) << 10); src++; src_size -= sizeof(unicode_t); } } } encoded_size = codepoint_write(codepoint, &dst, &dst_size); if (encoded_size == 0) { UTF8_SET_ERROR(NOT_ENOUGH_SPACE); return bytes_written; } bytes_written += encoded_size; src++; src_size -= sizeof(unicode_t); } return bytes_written; invaliddata: if (dst != 0) { if (dst_size < REPLACEMENT_CHARACTER_STRING_LENGTH) { UTF8_SET_ERROR(NOT_ENOUGH_SPACE); return bytes_written; } /* Write replacement codepoint to output */ memcpy(dst, REPLACEMENT_CHARACTER_STRING, REPLACEMENT_CHARACTER_STRING_LENGTH); } UTF8_SET_ERROR(INVALID_DATA); return bytes_written + REPLACEMENT_CHARACTER_STRING_LENGTH; } size_t widetoutf8(const wchar_t* input, size_t inputSize, char* target, size_t targetSize, int32_t* errors) { #if UTF8_WCHAR_UTF16 return utf16toutf8((const utf16_t*)input, inputSize, target, targetSize, errors); #elif UTF8_WCHAR_UTF32 return utf32toutf8((const unicode_t*)input, inputSize, target, targetSize, errors); #else return SIZE_MAX; #endif } size_t utf8toutf16(const char* input, size_t inputSize, utf16_t* target, size_t targetSize, int32_t* errors) { const char* src; size_t src_size; utf16_t* dst; size_t dst_size; size_t bytes_written = 0; /* Validate parameters */ UTF8_VALIDATE_PARAMETERS(char, utf16_t, bytes_written); /* Setup cursors */ src = input; src_size = inputSize; dst = target; dst_size = targetSize; /* Loop over input */ while (src_size > 0) { unicode_t decoded; uint8_t decoded_size = codepoint_read(src, src_size, &decoded); if (decoded <= MAX_BASIC_MULTILINGUAL_PLANE) { /* Codepoint fits in a single UTF-16 codepoint */ if (dst != 0) { /* Write to output */ if (dst_size < sizeof(utf16_t)) { UTF8_SET_ERROR(NOT_ENOUGH_SPACE); return bytes_written; } *dst++ = (utf16_t)decoded; dst_size -= sizeof(utf16_t); } bytes_written += sizeof(utf16_t); } else { /* Codepoint must be encoded using a surrogate pair */ if (dst != 0) { /* Write to output */ if (dst_size < 2 * sizeof(utf16_t)) { UTF8_SET_ERROR(NOT_ENOUGH_SPACE); return bytes_written; } /* Encoded value is always beyond BMP */ decoded -= (MAX_BASIC_MULTILINGUAL_PLANE + 1); *dst++ = SURROGATE_HIGH_START + (utf16_t) (decoded >> 10); *dst++ = SURROGATE_LOW_START + (decoded & 0x03FF); dst_size -= 2 * sizeof(utf16_t); } bytes_written += 2 * sizeof(utf16_t); } src += decoded_size; src_size -= decoded_size; } UTF8_SET_ERROR(NONE); return bytes_written; } size_t utf8toutf32(const char* input, size_t inputSize, unicode_t* target, size_t targetSize, int32_t* errors) { const char* src; size_t src_size; unicode_t* dst; size_t dst_size; size_t bytes_written = 0; /* Validate parameters */ UTF8_VALIDATE_PARAMETERS(char, unicode_t, bytes_written); /* Setup cursors */ src = input; src_size = inputSize; dst = target; dst_size = targetSize; /* Loop over input */ while (src_size > 0) { unicode_t decoded; uint8_t decoded_length = codepoint_read(src, src_size, &decoded); if (dst != 0) { /* Write to output */ if (dst_size < sizeof(unicode_t)) { UTF8_SET_ERROR(NOT_ENOUGH_SPACE); return bytes_written; } *dst++ = decoded; dst_size -= sizeof(unicode_t); } bytes_written += sizeof(unicode_t); src += decoded_length; src_size -= decoded_length; } UTF8_SET_ERROR(NONE); return bytes_written; } size_t utf8towide(const char* input, size_t inputSize, wchar_t* target, size_t targetSize, int32_t* errors) { #if UTF8_WCHAR_UTF16 return utf8toutf16(input, inputSize, (utf16_t*)target, targetSize, errors); #elif UTF8_WCHAR_UTF32 return utf8toutf32(input, inputSize, (unicode_t*)target, targetSize, errors); #else return SIZE_MAX; #endif } const char* utf8seek(const char* text, size_t textSize, const char* textStart, off_t offset, int direction) { const char* text_end; if (text == 0 || textStart == 0) { return text; } text_end = textStart + textSize; switch (direction) { case SEEK_CUR: { if (offset == 0) { return text; } else if (offset > 0) { return seeking_forward(text, text_end, textSize, offset); } else { return seeking_rewind(textStart, text, textSize, offset); } } break; case SEEK_SET: { if (text < textStart) { return text; } return seeking_forward(textStart, text_end, textSize, offset); } break; case SEEK_END: return seeking_rewind(textStart, text_end, textSize, -offset); default: return text; } } UTF8_API size_t utf8envlocale() { /* Sources for locales and code pages Windows https://msdn.microsoft.com/en-US/goglobal/bb896001.aspx POSIX https://www-01.ibm.com/support/knowledgecenter/ssw_aix_61/com.ibm.aix.nlsgdrf/support_languages_locales.htm */ #if WIN32 || _WINDOWS #define UTF8_LOCALE_CHECK(_name, _ansiCodepage, _oemCodepage) \ (codepage == _ansiCodepage || codepage == _oemCodepage) // Microsoft changed the name of the codepage member in VS2015. #if _MSC_VER >= 1800 #define UTF8_CODEPAGE_GET(_locale) ((__crt_locale_data_public*)(_locale)->locinfo)->_locale_lc_codepage #else #define UTF8_CODEPAGE_GET(_locale) (_locale)->locinfo->lc_codepage #endif unsigned int codepage; _locale_t locale = _get_current_locale(); if (locale == 0) { return UTF8_LOCALE_DEFAULT; } codepage = UTF8_CODEPAGE_GET(locale); #else #define UTF8_LOCALE_CHECK(_name, _ansiCodepage, _oemCodepage) \ !strncasecmp(locale, _name, 5) const char* locale = setlocale(LC_ALL, 0); if (locale == 0) { return UTF8_LOCALE_DEFAULT; } #endif if (UTF8_LOCALE_CHECK("lt_lt", 1257, 775)) { return UTF8_LOCALE_LITHUANIAN; } else if ( UTF8_LOCALE_CHECK("tr_tr", 1254, 857) || UTF8_LOCALE_CHECK("az_az", 1254, 857)) { return UTF8_LOCALE_TURKISH_AND_AZERI_LATIN; } return UTF8_LOCALE_DEFAULT; } size_t utf8toupper(const char* input, size_t inputSize, char* target, size_t targetSize, size_t locale, int32_t* errors) { CaseMappingState state; /* Validate parameters */ UTF8_VALIDATE_PARAMETERS_CHAR(char, 0); /* Initialize case mapping */ if (!casemapping_initialize( &state, input, inputSize, target, targetSize, UppercaseIndex1Ptr, UppercaseIndex2Ptr, UppercaseDataPtr, QuickCheckCaseMapped_Uppercase, locale, errors)) { return state.total_bytes_needed; } /* Execute case mapping as long as input remains */ while (state.src_size > 0) { size_t converted; if ((converted = casemapping_execute(&state, errors)) == 0) { return state.total_bytes_needed; } state.total_bytes_needed += converted; } UTF8_SET_ERROR(NONE); return state.total_bytes_needed; } size_t utf8tolower(const char* input, size_t inputSize, char* target, size_t targetSize, size_t locale, int32_t* errors) { CaseMappingState state; /* Validate parameters */ UTF8_VALIDATE_PARAMETERS_CHAR(char, 0); /* Initialize case mapping */ if (!casemapping_initialize( &state, input, inputSize, target, targetSize, LowercaseIndex1Ptr, LowercaseIndex2Ptr, LowercaseDataPtr, QuickCheckCaseMapped_Lowercase, locale, errors)) { return state.total_bytes_needed; } /* Execute case mapping as long as input remains */ while (state.src_size > 0) { size_t converted; if ((converted = casemapping_execute(&state, errors)) == 0) { return state.total_bytes_needed; } state.total_bytes_needed += converted; } UTF8_SET_ERROR(NONE); return state.total_bytes_needed; } size_t utf8totitle(const char* input, size_t inputSize, char* target, size_t targetSize, size_t locale, int32_t* errors) { CaseMappingState state; /* Validate parameters */ UTF8_VALIDATE_PARAMETERS_CHAR(char, 0); /* Initialize case mapping */ if (!casemapping_initialize( &state, input, inputSize, target, targetSize, TitlecaseIndex1Ptr, TitlecaseIndex2Ptr, TitlecaseDataPtr, QuickCheckCaseMapped_Titlecase, locale, errors)) { return state.total_bytes_needed; } /* Execute case mapping as long as input remains */ while (state.src_size > 0) { size_t converted; if ((converted = casemapping_execute(&state, errors)) == 0) { return state.total_bytes_needed; } /* The first letter of every word should be titlecase, the rest should be converted to lowercase. */ if (state.last_canonical_combining_class == CCC_NOT_REORDERED) { if (state.property_data == TitlecaseDataPtr) { if ((state.last_general_category & UTF8_CATEGORY_LETTER) != 0) { state.property_index1 = LowercaseIndex1Ptr; state.property_index2 = LowercaseIndex2Ptr; state.property_data = LowercaseDataPtr; state.quickcheck_flags = QuickCheckCaseMapped_Lowercase; } } else if ( (state.last_general_category & UTF8_CATEGORY_LETTER) == 0) { state.property_index1 = TitlecaseIndex1Ptr; state.property_index2 = TitlecaseIndex2Ptr; state.property_data = TitlecaseDataPtr; state.quickcheck_flags = QuickCheckCaseMapped_Titlecase; } } state.total_bytes_needed += converted; } UTF8_SET_ERROR(NONE); return state.total_bytes_needed; } size_t utf8casefold(const char* input, size_t inputSize, char* target, size_t targetSize, size_t locale, int32_t* errors) { CaseMappingState state; /* Validate parameters */ UTF8_VALIDATE_PARAMETERS_CHAR(char, 0); /* Initialize case mapping */ if (!casemapping_initialize( &state, input, inputSize, target, targetSize, CaseFoldingIndex1Ptr, CaseFoldingIndex2Ptr, CaseFoldingDataPtr, QuickCheckCaseMapped_Casefolded, locale, errors)) { return state.total_bytes_needed; } if (state.locale == UTF8_LOCALE_TURKISH_AND_AZERI_LATIN) { /* Exceptional behavior for Turkish and Azerbaijani (Latin) locales */ while (state.src_size > 0) { const char* resolved = 0; uint8_t bytes_needed = 0; /* Read next code point */ if (state.last_code_point_size = codepoint_read(state.src, state.src_size, &state.last_code_point), state.last_code_point_size) { goto invaliddata; } /* Move source cursor */ if (state.src_size >= state.last_code_point_size) { state.src += state.last_code_point_size; state.src_size -= state.last_code_point_size; } else { state.src_size = 0; } /* Resolve case folding */ if ((PROPERTY_GET_CM(state.last_code_point) & QuickCheckCaseMapped_Casefolded) != 0) { if (state.last_code_point == CP_LATIN_CAPITAL_LETTER_I) { resolved = "\xC4\xB1"; bytes_needed = 2; } else if ( state.last_code_point == CP_LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE) { resolved = "i"; bytes_needed = 1; } else { resolved = database_querydecomposition(state.last_code_point, state.property_index1, state.property_index2, state.property_data, &bytes_needed); } } /* Write to output */ if (resolved != 0) { /* Write resolved string to output */ if (state.dst != 0) { if (state.dst_size < bytes_needed) { goto outofspace; } memcpy(state.dst, resolved, bytes_needed); state.dst += bytes_needed; state.dst_size -= bytes_needed; } } else { /* Write code point unchanged to output */ if (bytes_needed = codepoint_write(state.last_code_point, &state.dst, &state.dst_size), !bytes_needed) { goto outofspace; } } state.total_bytes_needed += bytes_needed; } } else { /* Execute case mapping as long as input remains */ while (state.src_size > 0) { const char* resolved = 0; uint8_t bytes_needed = 0; /* Read next code point */ if (state.last_code_point_size = codepoint_read(state.src, state.src_size, &state.last_code_point), state.last_code_point_size) { goto invaliddata; } /* Move source cursor */ if (state.src_size >= state.last_code_point_size) { state.src += state.last_code_point_size; state.src_size -= state.last_code_point_size; } else { state.src_size = 0; } /* Resolve case folding */ if ((PROPERTY_GET_CM(state.last_code_point) & QuickCheckCaseMapped_Casefolded) != 0) { resolved = database_querydecomposition(state.last_code_point, state.property_index1, state.property_index2, state.property_data, &bytes_needed); } if (resolved != 0) { /* Write resolved string to output */ if (state.dst != 0) { if (state.dst_size < bytes_needed) { goto outofspace; } memcpy(state.dst, resolved, bytes_needed); state.dst += bytes_needed; state.dst_size -= bytes_needed; } } else { /* Write code point unchanged to output */ if (bytes_needed = codepoint_write(state.last_code_point, &state.dst, &state.dst_size), bytes_needed) { goto outofspace; } } state.total_bytes_needed += bytes_needed; } } UTF8_SET_ERROR(NONE); return state.total_bytes_needed; invaliddata: UTF8_SET_ERROR(INVALID_DATA); return state.total_bytes_needed; outofspace: UTF8_SET_ERROR(NOT_ENOUGH_SPACE); return state.total_bytes_needed; } uint8_t utf8isnormalized(const char* input, size_t inputSize, size_t flags, size_t* offset) { const char* src = input; size_t src_size = inputSize; uint8_t last_canonical_class = CCC_NOT_REORDERED; size_t found_offset = 0; uint8_t result = UTF8_NORMALIZATION_RESULT_YES; unicode_t decoded; uint8_t canonical_class; uint8_t quick_check; const size_t* property_index; const uint8_t* property_data; /* Validate input and flags */ if (input == NULL || inputSize == 0 || (flags & (UTF8_NORMALIZE_DECOMPOSE | UTF8_NORMALIZE_COMPOSE)) == 0) { goto end; } /* Get properties */ if ((flags & UTF8_NORMALIZE_COMPOSE) != 0) { if ((flags & UTF8_NORMALIZE_COMPATIBILITY) != 0) { property_index = QuickCheckNFKCIndexPtr; property_data = QuickCheckNFKCDataPtr; } else { property_index = QuickCheckNFCIndexPtr; property_data = QuickCheckNFCDataPtr; } } else { if ((flags & UTF8_NORMALIZE_COMPATIBILITY) != 0) { property_index = QuickCheckNFKDIndexPtr; property_data = QuickCheckNFKDDataPtr; } else { property_index = QuickCheckNFDIndexPtr; property_data = QuickCheckNFDDataPtr; } } /* Process input */ while (src_size > 0) { /* Read codepoint at cursor */ uint8_t read = codepoint_read(src, src_size, &decoded); if (read == 0) { break; } /* Get canonical combining class and quick check value */ canonical_class = PROPERTY_GET_CCC(decoded); quick_check = PROPERTY_GET(property_index, property_data, decoded); /* Compare CCC to previous CCC */ if (last_canonical_class > canonical_class && canonical_class > CCC_NOT_REORDERED) { result = UTF8_NORMALIZATION_RESULT_NO; break; } /* Compare quick check value */ if (quick_check == QuickCheckResult_No) { result = UTF8_NORMALIZATION_RESULT_NO; break; } else if ( quick_check == QuickCheckResult_Maybe) { result = UTF8_NORMALIZATION_RESULT_MAYBE; } /* Append to offset */ if (result != UTF8_NORMALIZATION_RESULT_MAYBE) { found_offset += read; } last_canonical_class = canonical_class; src += read; src_size -= read; } end: if (offset != 0) { *offset = found_offset; } return result; } size_t utf8normalize(const char* input, size_t inputSize, char* target, size_t targetSize, size_t flags, int32_t* errors) { char* dst = target; size_t dst_size = targetSize; StreamState stream[4]; DecomposeState decompose_state; ComposeState compose_state = { 0 }; uint8_t compatibility = (flags & UTF8_NORMALIZE_COMPATIBILITY) != 0; StreamState* stream_output; uint8_t finished = 0; size_t bytes_written = 0; /* Decomposition uses the following process: input --> stream[0] --> (decompose) --> stream[1] --> (accumulate) --> stream[2] --> output The accumulation step is necessary in order to prevent buffer overflow attacks. Composition adds another stream buffer: input --> stream[0] --> (decompose) --> stream[1] --> (accumulate) --> stream[2] --> (compose) --> stream[3] --> output Although four streaming buffers may seem excessive, they are necessary for preventing allocations on the heap. */ /* Check for valid flags */ if ((flags & (UTF8_NORMALIZE_DECOMPOSE | UTF8_NORMALIZE_COMPOSE)) == 0) { UTF8_SET_ERROR(INVALID_FLAG); return bytes_written; } /* Validate parameters */ UTF8_VALIDATE_PARAMETERS_CHAR(char, bytes_written); /* Initialize decomposition */ memset(stream, 0, sizeof(stream)); if (!stream_initialize(&stream[0], input, inputSize) || !decompose_initialize(&decompose_state, &stream[0], &stream[1], compatibility)) { UTF8_SET_ERROR(INVALID_DATA); return bytes_written; } stream_output = &stream[2]; if ((flags & UTF8_NORMALIZE_COMPOSE) != 0) { /* Initialize composition */ if (!compose_initialize(&compose_state, &stream[2], &stream[3], compatibility)) { UTF8_SET_ERROR(INVALID_DATA); return bytes_written; } stream_output = &stream[3]; } do { uint8_t write = 0; /* Accumulate decomposed input in next stream */ if (stream[1].current > 0) { unicode_t* src_codepoint = stream[1].codepoint; unicode_t* dst_codepoint = stream[2].codepoint + stream[2].filled; uint8_t* src_qc = stream[1].quick_check; uint8_t* dst_qc = stream[2].quick_check + stream[2].filled; uint8_t* src_ccc = stream[1].canonical_combining_class; uint8_t* dst_ccc = stream[2].canonical_combining_class + stream[2].filled; if ((flags & UTF8_NORMALIZE_COMPOSE) != 0) { uint8_t i; /* Update stream properties to use composition values */ for (i = 0; i < stream[1].current; ++i) { *dst_qc++ = PROPERTY_GET(compose_state.qc_index, compose_state.qc_data, *src_codepoint); *dst_ccc++ = *src_ccc++; *dst_codepoint++ = *src_codepoint++; } } else { /* Copy directly */ memcpy(dst_codepoint, src_codepoint, stream[1].current * sizeof(unicode_t)); memcpy(dst_qc, src_qc, stream[1].current * sizeof(uint8_t)); memcpy(dst_ccc, src_ccc, stream[1].current * sizeof(uint8_t)); } stream[2].current += stream[1].current; stream[2].filled += stream[1].current; } /* Decompose input sequence into next stream */ finished = !decompose_execute(&decompose_state); if (!finished) { /* Output current stream it it could overflow accumulation buffer */ write = (stream[1].current + stream[2].filled) >= STREAM_SAFE_MAX; } /* Reorder potentially unordered decomposed stream */ if (!stream[1].stable) { stream_reorder(&stream[1]); } /* Write stream to output when overflowing or when accumulation buffer is empty*/ if (write || finished) { uint8_t i; /* Compose accumulation buffer */ if ((flags & UTF8_NORMALIZE_COMPOSE) != 0 && !compose_execute(&compose_state)) { break; } /* Write to output buffer */ for (i = 0; i < stream_output->current; ++i) { uint8_t encoded_size = codepoint_write(stream_output->codepoint[i], &dst, &dst_size); if (encoded_size == 0) { UTF8_SET_ERROR(NOT_ENOUGH_SPACE); return bytes_written; } bytes_written += encoded_size; } /* Reset accumulation buffer */ stream[2].current = 0; stream[2].filled = 0; } } while (!finished); UTF8_SET_ERROR(NONE); return bytes_written; } size_t utf8iscategory(const char* input, size_t inputSize, size_t flags) { const char* src = input; size_t src_size = inputSize; if (input == 0 || inputSize == 0) { return 0; } while (src_size > 0) { unicode_t code_point; uint32_t general_category; uint8_t canonical_combining_class; uint8_t offset; /* Compatibility fixes */ if ((flags & UTF8_CATEGORY_COMPATIBILITY) != 0 && *src < MAX_BASIC_LATIN) { if (flags == UTF8_CATEGORY_ISBLANK) { if (*src == 0x09) { /* CHARACTER TABULATION */ src++; src_size--; continue; } else if ( *src == 0x20) { /* SPACE */ src++; src_size--; continue; } else { break; } } else if ( flags == UTF8_CATEGORY_ISSPACE) { if (*src < 0x09 || *src > 0x20) { break; } else if ( *src <= 0x0D) { /* CHARACTER TABULATION ... CARRIAGE RETURN (CR) */ src++; src_size--; continue; } else if ( *src == 0x20) { /* SPACE */ src++; src_size--; continue; } else { break; } } else if ( flags == UTF8_CATEGORY_ISXDIGIT) { if (*src < 0x30 || *src > 0x66) { break; } else if ( *src <= 0x39) { /* DIGIT ZERO ... DIGIT NINE */ src++; src_size--; continue; } else if ( *src >= 0x41 && *src <= 0x46) { /* LATIN CAPITAL LETTER A ... LATIN CAPITAL LETTER F */ src++; src_size--; continue; } else if ( *src >= 0x61) { /* LATIN SMALL LETTER A ... LATIN SMALL LETTER F */ src++; src_size--; continue; } else { break; } } } /* Read next code point */ offset = codepoint_read(src, src_size, &code_point); /* Match General Category against flags */ general_category = PROPERTY_GET_GC(code_point); if ((general_category & flags) == 0 && /* Check for the start of the next grapheme cluster */ ((flags & UTF8_CATEGORY_IGNORE_GRAPHEME_CLUSTER) != 0 || (canonical_combining_class = PROPERTY_GET_CCC(code_point)) == CCC_NOT_REORDERED)) { break; } /* Move source cursor */ if (offset > src_size) { break; } src += offset; src_size -= offset; } return src - input; } ================================================ FILE: issues.md ================================================ # Issues Note: this is just a personal log of outstanding issues, shorter rants/ramblings, and a changelog that doesn't need me to scroll through git. ## FEATURES TO IMPLEMENT 2. Destructors for classes 5. String operators 6. Location information for type specifiers in definitions 7. 'cases' member of enums to enable runtime enumeration of... the enumeration. 8. Operator overloading for assignment and subscript/slice 14. Multi-dimensional arrays, as opposed to our current 'array-of-arrays' approach eg. index with `foo[a, b, c]` instead of `foo[a][b][c]` 16. `[[noreturn]]` for functions, so we don't error when no value is returned (eg. when calling `abort()`) 18. Some way of handling both types and expressions in `sizeof`/`typeid`/`typeof`. Might work if we just check for identifiers, but then what about polymorphic types? Those won't even parse as expressions. ----- ## THINGS TO FIX 2. There are still some instances where we explicitly 'initialise' a class equivalent to `memset(0)` -- see *THINGS TO NOTE* below. ------ ## THINGS TO INVESTIGATE * ### Possibly allow struct-constructors to init transparent fields * ### Errors need to propagate better Right now with the newly-implemented `PrettyError` system, we can propagate a lot more information upwards, and with the new thing of throwing an error when we unwrap a `TCResult`, there's less need to be explicit when handling errors during typechecking. Unfortunately, for a simple failed generic function instantiation, we get a mess like this: ``` (supertiny.flx:159:37) Error: No such function named 'foo' (in scope 'supertiny.main().__anon_scope_0') let k = foo(10, 20) ^ (supertiny.flx:159:37) Error: No viable candidates in attempted instantiation of parametric entity 'foo'; candidates are: let k = foo(10, 20) ^ (supertiny.flx:159:37) Error: Parametric entity 'foo' does not have an argument 'G' let k = foo(10, 20) ^ (supertiny.flx:157:13) Note: 'foo' was defined here: fn foo(a: T, b: T) -> T { return a + b } ``` Which is counter to our goal of having readable error messages even in the face of failed template instantiations (looking at you, C++) Possibly we need more 'kinds' of errors, where we can have boilerplate prefixes like `Candidate not suitable: `, rather than cascading multiple errors (most of them should be `info` anyway, and not errors), and also the possiblity of just posting text without the `Error`/`Warning` etc prefix. Also, we should be able to control the context-printing of each of those as well. * ### Certain cases we still allow a zeroinitialised class to exist: A. When growing a dynamic array, the new elements are zeroinitialised instead of having a value set (for non-class types, they get their default value) B. When initialising a field in a struct, if not explicitly assigned to it is left as it is -- which should be the zeroinitialiser C. When initialising a field in a class without an inline initialiser, we explicitly set it to 0. We either document this properly, or change the behaviour. I don't really want to devolve into the C++ style of forcing super-explicit initialiser syntax. However, we can enforce setting a value by forcing an inline initialiser for classes. For structs, we have 2 options -- 1: screw it, just make a zeroinit class if they appear in a struct; 2: only allow initialising structs with constructers that specify a value for any class types. For the former, I'm more inclined to do that, but the latter is more 'correct', as it were. Unfortunately, that would also mean disallowing `var foo: SomeStruct` without an initialiser... * ### Some kind of construct to make a variable immutable beyond a certain point thus you could have arbitrarily complex initialisation code, then have the compiler enforce that your variable is immutable after that point, eg: ``` var k = ... if(some_cond1) k = get_value() else k = get_other_value() k.mutating_func() make_immutable(k) k = ... // will not compile ``` * ### Type inference for single-expr functions? It's a little weird to have two arrows like this: `fn foo(a: T) -> T => a * a` The type inference would require some re-working though, because to generate the declaration of the function we need the return type, but to get the return type in this situation we need to typecheck the function body. Albeit it's a single expression, there might still be unresolved or unresolvable things inside the body. Possibly investigate whether we can do the typechecking in the generateDecl function?? But it's highly likely we separated those for a reason, so I don't think it's doable at this point. It's not really a high-priority thing anyway. * ### wrt. optional arguments you *must* refer to it by name to specify a value. For example: `fn foo(a: int, b: int = 3) => ...` ``` // valid combinations: foo(30) foo(a: 30) foo(30, b: 5) foo(a: 30, b: 1) // invalid combinations: foo(a: 30, 1) <-- cannot have positional arguments after named ones foo(30, 7) <-- must name the optional argument 'b' ``` * https://proandroiddev.com/understanding-generics-and-variance-in-kotlin-714c14564c47 https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science) * Arguments-after-varargs (see https://youtu.be/mGe5d6dPHAU?t=1379) Basically, allow passing named parameters after var-args. * Optimisation: use interned strings for comparison (and for use as keys in all the hashmaps we have), hopefully allowing a large-ish speedup since (according to historical profiles) `std::string`-related things are the cause of a lot of slowdowns. * Right now we design the `any` type to not handle refcounted types at all -- meaning it doesn't touch the refcount of those, and thus the `any` can outlive the referred-to value. To change this, `any` itself would need to be refcounted, but then we'd need to be able to check whether something was refcounted ** AT RUNTIME **, which is a whole bucket of shit I don't want to deal with yet. So for now, we are documenting that `any` does not care about reference counting, and deal with it later. * A similar issue with refcounting for casting, though i'm not entirely sure if this is a real issue or just something that i'm imagining. So, when we assign something `x = y`, then it is necessary that the types of `x` and `y` are the same. Then, if the type in question is a reference counted type, we do some `autoAssignRefCountedValue()`, that does separate things for lvalues and rvalues. If the right-hand side is an lvalue, then we increment its reference count; else, we perform a 'move' of the rvalue by removing it from the reference-counting stack. The problem comes when we need to cast `y` to the type of `x`. If we had to do a cast, that means that we transform the (potential) rhs-lvalue into an rvalue. This means that, if the rhs was originally an lvalue, we would try to remove the output of the casting op from the refcounting stack, which it doesn't exist in. So, we will add the output of the casting op to the refcounting list, if the output type is reference counted. The issue comes with how we handle the reference count of the *original* rhs. The potential cases that I can think of where we might get some trouble involves `any`: ```rust let x = string("hello") let b: any = x ``` In this case, `x` is an lvalue that gets casted to an rvalue of type `any`. In the assignment, we remove the casted rvalue from the rc-stack, (assuming we implement the fix above), then just do the store. ```rust let x: any = string("world") let y = x as string ``` In this case, it's a similar thing; if we apply the mentioned fix, I don't *see* any issues... TODO: actually investigate this properly. ----- ## POLYMORPHIC PIPELINE DOCUMENTATION So, this thing serves as the shitty documentation for how the generic pipeline works for future implementations. 1. When AST nodes are typechecked at the top level, if they are polymorphic things they will refuse to be checked, and won't return a result (`ast::Block` does the same check), but instead add themselves to a list of pending, uninstantiated generic types in the `sst::StateTree`. 2. When resolving a reference (function call or identifier), we check the pending generic list if we can't find any normal things that match (or if we already have some explicit mappings). If there is a match, we call into `attemptToDisambiguateGenericReference()` with whatever information we have (eg. partial solutions) 3. We call `inferTypesForGenericEntity` which is the main solver function that infers types for the type arguments that are missing. This just acts like a black box for the most part. 4. If we find that we're actually a reference to a function (ie. we act like a function pointer instead of a call) then we do a thing called `fillGenericTypeWithPlaceholders` which puts in fake 'solutions' for each type argument (aka `fir::PolyPlaceholderType`), and proceeds to return it. 5. We will then allow that to typecheck. For now, only functions can have placeholder types, so we special-case that in function typechecking by just skipping the body typecheck when we have placeholders. 6. Once we manage to solve everything -- ie. get rid of all the placeholder types, we need to re-typecheck the original definition with proper filled in types. This happens in `resolveFunctionCall`. ================================================ FILE: libs/OpenGL/GL.flx ================================================ // GL.flx // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. public enum GL: u32 { case FALSE = 0 case TRUE = 1 case BYTE = 0x1400 case UNSIGNED_BYTE = 0x1401 case SHORT = 0x1402 case UNSIGNED_SHORT = 0x1403 case INT = 0x1404 case UNSIGNED_INT = 0x1405 case FLOAT = 0x1406 case TWO_BYTES = 0x1407 case THREE_BYTES = 0x1408 case FOUR_BYTES = 0x1409 case DOUBLE = 0x140A case POINTS = 0x0000 case LINES = 0x0001 case LINE_LOOP = 0x0002 case LINE_STRIP = 0x0003 case TRIANGLES = 0x0004 case TRIANGLE_STRIP = 0x0005 case TRIANGLE_FAN = 0x0006 case QUADS = 0x0007 case QUAD_STRIP = 0x0008 case POLYGON = 0x0009 case VERTEX_ARRAY = 0x8074 case NORMAL_ARRAY = 0x8075 case COLOR_ARRAY = 0x8076 case INDEX_ARRAY = 0x8077 case TEXTURE_COORD_ARRAY = 0x8078 case EDGE_FLAG_ARRAY = 0x8079 case VERTEX_ARRAY_SIZE = 0x807A case VERTEX_ARRAY_TYPE = 0x807B case VERTEX_ARRAY_STRIDE = 0x807C case NORMAL_ARRAY_TYPE = 0x807E case NORMAL_ARRAY_STRIDE = 0x807F case COLOR_ARRAY_SIZE = 0x8081 case COLOR_ARRAY_TYPE = 0x8082 case COLOR_ARRAY_STRIDE = 0x8083 case INDEX_ARRAY_TYPE = 0x8085 case INDEX_ARRAY_STRIDE = 0x8086 case TEXTURE_COORD_ARRAY_SIZE = 0x8088 case TEXTURE_COORD_ARRAY_TYPE = 0x8089 case TEXTURE_COORD_ARRAY_STRIDE = 0x808A case EDGE_FLAG_ARRAY_STRIDE = 0x808C case VERTEX_ARRAY_POINTER = 0x808E case NORMAL_ARRAY_POINTER = 0x808F case COLOR_ARRAY_POINTER = 0x8090 case INDEX_ARRAY_POINTER = 0x8091 case TEXTURE_COORD_ARRAY_POINTER = 0x8092 case EDGE_FLAG_ARRAY_POINTER = 0x8093 case V2F = 0x2A20 case V3F = 0x2A21 case C4UB_V2F = 0x2A22 case C4UB_V3F = 0x2A23 case C3F_V3F = 0x2A24 case N3F_V3F = 0x2A25 case C4F_N3F_V3F = 0x2A26 case T2F_V3F = 0x2A27 case T4F_V4F = 0x2A28 case T2F_C4UB_V3F = 0x2A29 case T2F_C3F_V3F = 0x2A2A case T2F_N3F_V3F = 0x2A2B case T2F_C4F_N3F_V3F = 0x2A2C case T4F_C4F_N3F_V4F = 0x2A2D case MATRIX_MODE = 0x0BA0 case MODELVIEW = 0x1700 case PROJECTION = 0x1701 case TEXTURE = 0x1702 case POINT_SMOOTH = 0x0B10 case POINT_SIZE = 0x0B11 case POINT_SIZE_GRANULARITY = 0x0B13 case POINT_SIZE_RANGE = 0x0B12 case LINE_SMOOTH = 0x0B20 case LINE_STIPPLE = 0x0B24 case LINE_STIPPLE_PATTERN = 0x0B25 case LINE_STIPPLE_REPEAT = 0x0B26 case LINE_WIDTH = 0x0B21 case LINE_WIDTH_GRANULARITY = 0x0B23 case LINE_WIDTH_RANGE = 0x0B22 case POINT = 0x1B00 case LINE = 0x1B01 case FILL = 0x1B02 case CW = 0x0900 case CCW = 0x0901 case FRONT = 0x0404 case BACK = 0x0405 case POLYGON_MODE = 0x0B40 case POLYGON_SMOOTH = 0x0B41 case POLYGON_STIPPLE = 0x0B42 case EDGE_FLAG = 0x0B43 case CULL_FACE = 0x0B44 case CULL_FACE_MODE = 0x0B45 case FRONT_FACE = 0x0B46 case POLYGON_OFFSET_FACTOR = 0x8038 case POLYGON_OFFSET_UNITS = 0x2A00 case POLYGON_OFFSET_POINT = 0x2A01 case POLYGON_OFFSET_LINE = 0x2A02 case POLYGON_OFFSET_FILL = 0x8037 case COMPILE = 0x1300 case COMPILE_AND_EXECUTE = 0x1301 case LIST_BASE = 0x0B32 case LIST_INDEX = 0x0B33 case LIST_MODE = 0x0B30 case NEVER = 0x0200 case LESS = 0x0201 case EQUAL = 0x0202 case LEQUAL = 0x0203 case GREATER = 0x0204 case NOTEQUAL = 0x0205 case GEQUAL = 0x0206 case ALWAYS = 0x0207 case DEPTH_TEST = 0x0B71 case DEPTH_BITS = 0x0D56 case DEPTH_CLEAR_VALUE = 0x0B73 case DEPTH_FUNC = 0x0B74 case DEPTH_RANGE = 0x0B70 case DEPTH_WRITEMASK = 0x0B72 case DEPTH_COMPONENT = 0x1902 case LIGHTING = 0x0B50 case LIGHT0 = 0x4000 case LIGHT1 = 0x4001 case LIGHT2 = 0x4002 case LIGHT3 = 0x4003 case LIGHT4 = 0x4004 case LIGHT5 = 0x4005 case LIGHT6 = 0x4006 case LIGHT7 = 0x4007 case SPOT_EXPONENT = 0x1205 case SPOT_CUTOFF = 0x1206 case CONSTANT_ATTENUATION = 0x1207 case LINEAR_ATTENUATION = 0x1208 case QUADRATIC_ATTENUATION = 0x1209 case AMBIENT = 0x1200 case DIFFUSE = 0x1201 case SPECULAR = 0x1202 case SHININESS = 0x1601 case EMISSION = 0x1600 case POSITION = 0x1203 case SPOT_DIRECTION = 0x1204 case AMBIENT_AND_DIFFUSE = 0x1602 case COLOR_INDEXES = 0x1603 case LIGHT_MODEL_TWO_SIDE = 0x0B52 case LIGHT_MODEL_LOCAL_VIEWER = 0x0B51 case LIGHT_MODEL_AMBIENT = 0x0B53 case FRONT_AND_BACK = 0x0408 case SHADE_MODEL = 0x0B54 case FLAT = 0x1D00 case SMOOTH = 0x1D01 case COLOR_MATERIAL = 0x0B57 case COLOR_MATERIAL_FACE = 0x0B55 case COLOR_MATERIAL_PARAMETER = 0x0B56 case NORMALIZE = 0x0BA1 case CLIP_PLANE0 = 0x3000 case CLIP_PLANE1 = 0x3001 case CLIP_PLANE2 = 0x3002 case CLIP_PLANE3 = 0x3003 case CLIP_PLANE4 = 0x3004 case CLIP_PLANE5 = 0x3005 case ACCUM_RED_BITS = 0x0D58 case ACCUM_GREEN_BITS = 0x0D59 case ACCUM_BLUE_BITS = 0x0D5A case ACCUM_ALPHA_BITS = 0x0D5B case ACCUM_CLEAR_VALUE = 0x0B80 case ACCUM = 0x0100 case ADD = 0x0104 case LOAD = 0x0101 case MULT = 0x0103 case RETURN = 0x0102 case ALPHA_TEST = 0x0BC0 case ALPHA_TEST_REF = 0x0BC2 case ALPHA_TEST_FUNC = 0x0BC1 case BLEND = 0x0BE2 case BLEND_SRC = 0x0BE1 case BLEND_DST = 0x0BE0 case ZERO = 0 case ONE = 1 case SRC_COLOR = 0x0300 case ONE_MINUS_SRC_COLOR = 0x0301 case SRC_ALPHA = 0x0302 case ONE_MINUS_SRC_ALPHA = 0x0303 case DST_ALPHA = 0x0304 case ONE_MINUS_DST_ALPHA = 0x0305 case DST_COLOR = 0x0306 case ONE_MINUS_DST_COLOR = 0x0307 case SRC_ALPHA_SATURATE = 0x0308 case FEEDBACK = 0x1C01 case RENDER = 0x1C00 case SELECT = 0x1C02 case TWO_D = 0x0600 case THREE_D = 0x0601 case THREE_D_COLOR = 0x0602 case THREE_D_COLOR_TEXTURE = 0x0603 case FOUR_D_COLOR_TEXTURE = 0x0604 case POINT_TOKEN = 0x0701 case LINE_TOKEN = 0x0702 case LINE_RESET_TOKEN = 0x0707 case POLYGON_TOKEN = 0x0703 case BITMAP_TOKEN = 0x0704 case DRAW_PIXEL_TOKEN = 0x0705 case COPY_PIXEL_TOKEN = 0x0706 case PASS_THROUGH_TOKEN = 0x0700 case FEEDBACK_BUFFER_POINTER = 0x0DF0 case FEEDBACK_BUFFER_SIZE = 0x0DF1 case FEEDBACK_BUFFER_TYPE = 0x0DF2 case SELECTION_BUFFER_POINTER = 0x0DF3 case SELECTION_BUFFER_SIZE = 0x0DF4 case FOG = 0x0B60 case FOG_MODE = 0x0B65 case FOG_DENSITY = 0x0B62 case FOG_COLOR = 0x0B66 case FOG_INDEX = 0x0B61 case FOG_START = 0x0B63 case FOG_END = 0x0B64 case LINEAR = 0x2601 case EXP = 0x0800 case EXP2 = 0x0801 case LOGIC_OP = 0x0BF1 case INDEX_LOGIC_OP = 0x0BF1 case COLOR_LOGIC_OP = 0x0BF2 case LOGIC_OP_MODE = 0x0BF0 case CLEAR = 0x1500 case SET = 0x150F case COPY = 0x1503 case COPY_INVERTED = 0x150C case NOOP = 0x1505 case INVERT = 0x150A case AND = 0x1501 case NAND = 0x150E case OR = 0x1507 case NOR = 0x1508 case XOR = 0x1506 case EQUIV = 0x1509 case AND_REVERSE = 0x1502 case AND_INVERTED = 0x1504 case OR_REVERSE = 0x150B case OR_INVERTED = 0x150D case STENCIL_BITS = 0x0D57 case STENCIL_TEST = 0x0B90 case STENCIL_CLEAR_VALUE = 0x0B91 case STENCIL_FUNC = 0x0B92 case STENCIL_VALUE_MASK = 0x0B93 case STENCIL_FAIL = 0x0B94 case STENCIL_PASS_DEPTH_FAIL = 0x0B95 case STENCIL_PASS_DEPTH_PASS = 0x0B96 case STENCIL_REF = 0x0B97 case STENCIL_WRITEMASK = 0x0B98 case STENCIL_INDEX = 0x1901 case KEEP = 0x1E00 case REPLACE = 0x1E01 case INCR = 0x1E02 case DECR = 0x1E03 case NONE = 0 case LEFT = 0x0406 case RIGHT = 0x0407 case FRONT_LEFT = 0x0400 case FRONT_RIGHT = 0x0401 case BACK_LEFT = 0x0402 case BACK_RIGHT = 0x0403 case AUX0 = 0x0409 case AUX1 = 0x040A case AUX2 = 0x040B case AUX3 = 0x040C case COLOR_INDEX = 0x1900 case RED = 0x1903 case GREEN = 0x1904 case BLUE = 0x1905 case ALPHA = 0x1906 case LUMINANCE = 0x1909 case LUMINANCE_ALPHA = 0x190A case ALPHA_BITS = 0x0D55 case RED_BITS = 0x0D52 case GREEN_BITS = 0x0D53 case BLUE_BITS = 0x0D54 case INDEX_BITS = 0x0D51 case SUBPIXEL_BITS = 0x0D50 case AUX_BUFFERS = 0x0C00 case READ_BUFFER = 0x0C02 case DRAW_BUFFER = 0x0C01 case DOUBLEBUFFER = 0x0C32 case STEREO = 0x0C33 case BITMAP = 0x1A00 case COLOR = 0x1800 case DEPTH = 0x1801 case STENCIL = 0x1802 case DITHER = 0x0BD0 case RGB = 0x1907 case RGBA = 0x1908 case MAX_LIST_NESTING = 0x0B31 case MAX_EVAL_ORDER = 0x0D30 case MAX_LIGHTS = 0x0D31 case MAX_CLIP_PLANES = 0x0D32 case MAX_TEXTURE_SIZE = 0x0D33 case MAX_PIXEL_MAP_TABLE = 0x0D34 case MAX_ATTRIB_STACK_DEPTH = 0x0D35 case MAX_MODELVIEW_STACK_DEPTH = 0x0D36 case MAX_NAME_STACK_DEPTH = 0x0D37 case MAX_PROJECTION_STACK_DEPTH = 0x0D38 case MAX_TEXTURE_STACK_DEPTH = 0x0D39 case MAX_VIEWPORT_DIMS = 0x0D3A case MAX_CLIENT_ATTRIB_STACK_DEPTH = 0x0D3B case ATTRIB_STACK_DEPTH = 0x0BB0 case CLIENT_ATTRIB_STACK_DEPTH = 0x0BB1 case COLOR_CLEAR_VALUE = 0x0C22 case COLOR_WRITEMASK = 0x0C23 case CURRENT_INDEX = 0x0B01 case CURRENT_COLOR = 0x0B00 case CURRENT_NORMAL = 0x0B02 case CURRENT_RASTER_COLOR = 0x0B04 case CURRENT_RASTER_DISTANCE = 0x0B09 case CURRENT_RASTER_INDEX = 0x0B05 case CURRENT_RASTER_POSITION = 0x0B07 case CURRENT_RASTER_TEXTURE_COORDS = 0x0B06 case CURRENT_RASTER_POSITION_VALID = 0x0B08 case CURRENT_TEXTURE_COORDS = 0x0B03 case INDEX_CLEAR_VALUE = 0x0C20 case INDEX_MODE = 0x0C30 case INDEX_WRITEMASK = 0x0C21 case MODELVIEW_MATRIX = 0x0BA6 case MODELVIEW_STACK_DEPTH = 0x0BA3 case NAME_STACK_DEPTH = 0x0D70 case PROJECTION_MATRIX = 0x0BA7 case PROJECTION_STACK_DEPTH = 0x0BA4 case RENDER_MODE = 0x0C40 case RGBA_MODE = 0x0C31 case TEXTURE_MATRIX = 0x0BA8 case TEXTURE_STACK_DEPTH = 0x0BA5 case VIEWPORT = 0x0BA2 case AUTO_NORMAL = 0x0D80 case MAP1_COLOR_4 = 0x0D90 case MAP1_INDEX = 0x0D91 case MAP1_NORMAL = 0x0D92 case MAP1_TEXTURE_COORD_1 = 0x0D93 case MAP1_TEXTURE_COORD_2 = 0x0D94 case MAP1_TEXTURE_COORD_3 = 0x0D95 case MAP1_TEXTURE_COORD_4 = 0x0D96 case MAP1_VERTEX_3 = 0x0D97 case MAP1_VERTEX_4 = 0x0D98 case MAP2_COLOR_4 = 0x0DB0 case MAP2_INDEX = 0x0DB1 case MAP2_NORMAL = 0x0DB2 case MAP2_TEXTURE_COORD_1 = 0x0DB3 case MAP2_TEXTURE_COORD_2 = 0x0DB4 case MAP2_TEXTURE_COORD_3 = 0x0DB5 case MAP2_TEXTURE_COORD_4 = 0x0DB6 case MAP2_VERTEX_3 = 0x0DB7 case MAP2_VERTEX_4 = 0x0DB8 case MAP1_GRID_DOMAIN = 0x0DD0 case MAP1_GRID_SEGMENTS = 0x0DD1 case MAP2_GRID_DOMAIN = 0x0DD2 case MAP2_GRID_SEGMENTS = 0x0DD3 case COEFF = 0x0A00 case ORDER = 0x0A01 case DOMAIN = 0x0A02 case PERSPECTIVE_CORRECTION_HINT = 0x0C50 case POINT_SMOOTH_HINT = 0x0C51 case LINE_SMOOTH_HINT = 0x0C52 case POLYGON_SMOOTH_HINT = 0x0C53 case FOG_HINT = 0x0C54 case DONT_CARE = 0x1100 case FASTEST = 0x1101 case NICEST = 0x1102 case SCISSOR_BOX = 0x0C10 case SCISSOR_TEST = 0x0C11 case MAP_COLOR = 0x0D10 case MAP_STENCIL = 0x0D11 case INDEX_SHIFT = 0x0D12 case INDEX_OFFSET = 0x0D13 case RED_SCALE = 0x0D14 case RED_BIAS = 0x0D15 case GREEN_SCALE = 0x0D18 case GREEN_BIAS = 0x0D19 case BLUE_SCALE = 0x0D1A case BLUE_BIAS = 0x0D1B case ALPHA_SCALE = 0x0D1C case ALPHA_BIAS = 0x0D1D case DEPTH_SCALE = 0x0D1E case DEPTH_BIAS = 0x0D1F case PIXEL_MAP_S_TO_S_SIZE = 0x0CB1 case PIXEL_MAP_I_TO_I_SIZE = 0x0CB0 case PIXEL_MAP_I_TO_R_SIZE = 0x0CB2 case PIXEL_MAP_I_TO_G_SIZE = 0x0CB3 case PIXEL_MAP_I_TO_B_SIZE = 0x0CB4 case PIXEL_MAP_I_TO_A_SIZE = 0x0CB5 case PIXEL_MAP_R_TO_R_SIZE = 0x0CB6 case PIXEL_MAP_G_TO_G_SIZE = 0x0CB7 case PIXEL_MAP_B_TO_B_SIZE = 0x0CB8 case PIXEL_MAP_A_TO_A_SIZE = 0x0CB9 case PIXEL_MAP_S_TO_S = 0x0C71 case PIXEL_MAP_I_TO_I = 0x0C70 case PIXEL_MAP_I_TO_R = 0x0C72 case PIXEL_MAP_I_TO_G = 0x0C73 case PIXEL_MAP_I_TO_B = 0x0C74 case PIXEL_MAP_I_TO_A = 0x0C75 case PIXEL_MAP_R_TO_R = 0x0C76 case PIXEL_MAP_G_TO_G = 0x0C77 case PIXEL_MAP_B_TO_B = 0x0C78 case PIXEL_MAP_A_TO_A = 0x0C79 case PACK_ALIGNMENT = 0x0D05 case PACK_LSB_FIRST = 0x0D01 case PACK_ROW_LENGTH = 0x0D02 case PACK_SKIP_PIXELS = 0x0D04 case PACK_SKIP_ROWS = 0x0D03 case PACK_SWAP_BYTES = 0x0D00 case UNPACK_ALIGNMENT = 0x0CF5 case UNPACK_LSB_FIRST = 0x0CF1 case UNPACK_ROW_LENGTH = 0x0CF2 case UNPACK_SKIP_PIXELS = 0x0CF4 case UNPACK_SKIP_ROWS = 0x0CF3 case UNPACK_SWAP_BYTES = 0x0CF0 case ZOOM_X = 0x0D16 case ZOOM_Y = 0x0D17 case TEXTURE_ENV = 0x2300 case TEXTURE_ENV_MODE = 0x2200 case TEXTURE_1D = 0x0DE0 case TEXTURE_2D = 0x0DE1 case TEXTURE_WRAP_S = 0x2802 case TEXTURE_WRAP_T = 0x2803 case TEXTURE_MAG_FILTER = 0x2800 case TEXTURE_MIN_FILTER = 0x2801 case TEXTURE_ENV_COLOR = 0x2201 case TEXTURE_GEN_S = 0x0C60 case TEXTURE_GEN_T = 0x0C61 case TEXTURE_GEN_R = 0x0C62 case TEXTURE_GEN_Q = 0x0C63 case TEXTURE_GEN_MODE = 0x2500 case TEXTURE_BORDER_COLOR = 0x1004 case TEXTURE_WIDTH = 0x1000 case TEXTURE_HEIGHT = 0x1001 case TEXTURE_BORDER = 0x1005 case TEXTURE_COMPONENTS = 0x1003 case TEXTURE_RED_SIZE = 0x805C case TEXTURE_GREEN_SIZE = 0x805D case TEXTURE_BLUE_SIZE = 0x805E case TEXTURE_ALPHA_SIZE = 0x805F case TEXTURE_LUMINANCE_SIZE = 0x8060 case TEXTURE_INTENSITY_SIZE = 0x8061 case NEAREST_MIPMAP_NEAREST = 0x2700 case NEAREST_MIPMAP_LINEAR = 0x2702 case LINEAR_MIPMAP_NEAREST = 0x2701 case LINEAR_MIPMAP_LINEAR = 0x2703 case OBJECT_LINEAR = 0x2401 case OBJECT_PLANE = 0x2501 case EYE_LINEAR = 0x2400 case EYE_PLANE = 0x2502 case SPHERE_MAP = 0x2402 case DECAL = 0x2101 case MODULATE = 0x2100 case NEAREST = 0x2600 case REPEAT = 0x2901 case CLAMP = 0x2900 case S = 0x2000 case T = 0x2001 case R = 0x2002 case Q = 0x2003 case VENDOR = 0x1F00 case RENDERER = 0x1F01 case VERSION = 0x1F02 case EXTENSIONS = 0x1F03 case NO_ERROR = 0 case INVALID_ENUM = 0x0500 case INVALID_VALUE = 0x0501 case INVALID_OPERATION = 0x0502 case STACK_OVERFLOW = 0x0503 case STACK_UNDERFLOW = 0x0504 case OUT_OF_MEMORY = 0x0505 case CURRENT_BIT = 0x00000001 case POINT_BIT = 0x00000002 case LINE_BIT = 0x00000004 case POLYGON_BIT = 0x00000008 case POLYGON_STIPPLE_BIT = 0x00000010 case PIXEL_MODE_BIT = 0x00000020 case LIGHTING_BIT = 0x00000040 case FOG_BIT = 0x00000080 case DEPTH_BUFFER_BIT = 0x00000100 case ACCUM_BUFFER_BIT = 0x00000200 case STENCIL_BUFFER_BIT = 0x00000400 case VIEWPORT_BIT = 0x00000800 case TRANSFORM_BIT = 0x00001000 case ENABLE_BIT = 0x00002000 case COLOR_BUFFER_BIT = 0x00004000 case HINT_BIT = 0x00008000 case EVAL_BIT = 0x00010000 case LIST_BIT = 0x00020000 case TEXTURE_BIT = 0x00040000 case SCISSOR_BIT = 0x00080000 case ALL_ATTRIB_BITS = 0x000FFFFF // OpenGL 1.1 case PROXY_TEXTURE_1D = 0x8063 case PROXY_TEXTURE_2D = 0x8064 case TEXTURE_PRIORITY = 0x8066 case TEXTURE_RESIDENT = 0x8067 case TEXTURE_BINDING_1D = 0x8068 case TEXTURE_BINDING_2D = 0x8069 case TEXTURE_INTERNAL_FORMAT = 0x1003 case ALPHA4 = 0x803B case ALPHA8 = 0x803C case ALPHA12 = 0x803D case ALPHA16 = 0x803E case LUMINANCE4 = 0x803F case LUMINANCE8 = 0x8040 case LUMINANCE12 = 0x8041 case LUMINANCE16 = 0x8042 case LUMINANCE4_ALPHA4 = 0x8043 case LUMINANCE6_ALPHA2 = 0x8044 case LUMINANCE8_ALPHA8 = 0x8045 case LUMINANCE12_ALPHA4 = 0x8046 case LUMINANCE12_ALPHA12 = 0x8047 case LUMINANCE16_ALPHA16 = 0x8048 case INTENSITY = 0x8049 case INTENSITY4 = 0x804A case INTENSITY8 = 0x804B case INTENSITY12 = 0x804C case INTENSITY16 = 0x804D case R3_G3_B2 = 0x2A10 case RGB4 = 0x804F case RGB5 = 0x8050 case RGB8 = 0x8051 case RGB10 = 0x8052 case RGB12 = 0x8053 case RGB16 = 0x8054 case RGBA2 = 0x8055 case RGBA4 = 0x8056 case RGB5_A1 = 0x8057 case RGBA8 = 0x8058 case RGB10_A2 = 0x8059 case RGBA12 = 0x805A case RGBA16 = 0x805B case CLIENT_PIXEL_STORE_BIT = 0x00000001 case CLIENT_VERTEX_ARRAY_BIT = 0x00000002 case ALL_CLIENT_ATTRIB_BITS = 0xFFFFFFFF case CLIENT_ALL_ATTRIB_BITS = 0xFFFFFFFF // OpenGL 1.2 case RESCALE_NORMAL = 0x803A case CLAMP_TO_EDGE = 0x812F case MAX_ELEMENTS_VERTICES = 0x80E8 case MAX_ELEMENTS_INDICES = 0x80E9 case BGR = 0x80E0 case BGRA = 0x80E1 case UNSIGNED_BYTE_3_3_2 = 0x8032 case UNSIGNED_BYTE_2_3_3_REV = 0x8362 case UNSIGNED_SHORT_5_6_5 = 0x8363 case UNSIGNED_SHORT_5_6_5_REV = 0x8364 case UNSIGNED_SHORT_4_4_4_4 = 0x8033 case UNSIGNED_SHORT_4_4_4_4_REV = 0x8365 case UNSIGNED_SHORT_5_5_5_1 = 0x8034 case UNSIGNED_SHORT_1_5_5_5_REV = 0x8366 case UNSIGNED_INT_8_8_8_8 = 0x8035 case UNSIGNED_INT_8_8_8_8_REV = 0x8367 case UNSIGNED_INT_10_10_10_2 = 0x8036 case UNSIGNED_INT_2_10_10_10_REV = 0x8368 case LIGHT_MODEL_COLOR_CONTROL = 0x81F8 case SINGLE_COLOR = 0x81F9 case SEPARATE_SPECULAR_COLOR = 0x81FA case TEXTURE_MIN_LOD = 0x813A case TEXTURE_MAX_LOD = 0x813B case TEXTURE_BASE_LEVEL = 0x813C case TEXTURE_MAX_LEVEL = 0x813D case SMOOTH_POINT_SIZE_RANGE = 0x0B12 case SMOOTH_POINT_SIZE_GRANULARITY = 0x0B13 case SMOOTH_LINE_WIDTH_RANGE = 0x0B22 case SMOOTH_LINE_WIDTH_GRANULARITY = 0x0B23 case ALIASED_POINT_SIZE_RANGE = 0x846D case ALIASED_LINE_WIDTH_RANGE = 0x846E case PACK_SKIP_IMAGES = 0x806B case PACK_IMAGE_HEIGHT = 0x806C case UNPACK_SKIP_IMAGES = 0x806D case UNPACK_IMAGE_HEIGHT = 0x806E case TEXTURE_3D = 0x806F case PROXY_TEXTURE_3D = 0x8070 case TEXTURE_DEPTH = 0x8071 case TEXTURE_WRAP_R = 0x8072 case MAX_3D_TEXTURE_SIZE = 0x8073 case TEXTURE_BINDING_3D = 0x806A // GL_ARB_imaging case CONSTANT_COLOR = 0x8001 case ONE_MINUS_NT_COLOR = 0x8002 case CONSTANT_ALPHA = 0x8003 case ONE_MINUS_NT_ALPHA = 0x8004 case COLOR_TABLE = 0x80D0 case POST_CONVOLUTION_COLOR_TABLE = 0x80D1 case POST_COLOR_MATRIX_COLOR_TABLE = 0x80D2 case PROXY_COLOR_TABLE = 0x80D3 case PROXY_POST_CONVOLUTION_COLOR_TABLE = 0x80D4 case PROXY_POST_COLOR_MATRIX_COLOR_TABLE = 0x80D5 case COLOR_TABLE_SCALE = 0x80D6 case COLOR_TABLE_BIAS = 0x80D7 case COLOR_TABLE_FORMAT = 0x80D8 case COLOR_TABLE_WIDTH = 0x80D9 case COLOR_TABLE_RED_SIZE = 0x80DA case COLOR_TABLE_GREEN_SIZE = 0x80DB case COLOR_TABLE_BLUE_SIZE = 0x80DC case COLOR_TABLE_ALPHA_SIZE = 0x80DD case COLOR_TABLE_LUMINANCE_SIZE = 0x80DE case COLOR_TABLE_INTENSITY_SIZE = 0x80DF case CONVOLUTION_1D = 0x8010 case CONVOLUTION_2D = 0x8011 case SEPARABLE_2D = 0x8012 case CONVOLUTION_BORDER_MODE = 0x8013 case CONVOLUTION_FILTER_SCALE = 0x8014 case CONVOLUTION_FILTER_BIAS = 0x8015 case REDUCE = 0x8016 case CONVOLUTION_FORMAT = 0x8017 case CONVOLUTION_WIDTH = 0x8018 case CONVOLUTION_HEIGHT = 0x8019 case MAX_CONVOLUTION_WIDTH = 0x801A case MAX_CONVOLUTION_HEIGHT = 0x801B case POST_CONVOLUTION_RED_SCALE = 0x801C case POST_CONVOLUTION_GREEN_SCALE = 0x801D case POST_CONVOLUTION_BLUE_SCALE = 0x801E case POST_CONVOLUTION_ALPHA_SCALE = 0x801F case POST_CONVOLUTION_RED_BIAS = 0x8020 case POST_CONVOLUTION_GREEN_BIAS = 0x8021 case POST_CONVOLUTION_BLUE_BIAS = 0x8022 case POST_CONVOLUTION_ALPHA_BIAS = 0x8023 case CONSTANT_BORDER = 0x8151 case REPLICATE_BORDER = 0x8153 case CONVOLUTION_BORDER_COLOR = 0x8154 case COLOR_MATRIX = 0x80B1 case COLOR_MATRIX_STACK_DEPTH = 0x80B2 case MAX_COLOR_MATRIX_STACK_DEPTH = 0x80B3 case POST_COLOR_MATRIX_RED_SCALE = 0x80B4 case POST_COLOR_MATRIX_GREEN_SCALE = 0x80B5 case POST_COLOR_MATRIX_BLUE_SCALE = 0x80B6 case POST_COLOR_MATRIX_ALPHA_SCALE = 0x80B7 case POST_COLOR_MATRIX_RED_BIAS = 0x80B8 case POST_COLOR_MATRIX_GREEN_BIAS = 0x80B9 case POST_COLOR_MATRIX_BLUE_BIAS = 0x80BA case POST_COLOR_MATRIX_ALPHA_BIAS = 0x80BB case HISTOGRAM = 0x8024 case PROXY_HISTOGRAM = 0x8025 case HISTOGRAM_WIDTH = 0x8026 case HISTOGRAM_FORMAT = 0x8027 case HISTOGRAM_RED_SIZE = 0x8028 case HISTOGRAM_GREEN_SIZE = 0x8029 case HISTOGRAM_BLUE_SIZE = 0x802A case HISTOGRAM_ALPHA_SIZE = 0x802B case HISTOGRAM_LUMINANCE_SIZE = 0x802C case HISTOGRAM_SINK = 0x802D case MINMAX = 0x802E case MINMAX_FORMAT = 0x802F case MINMAX_SINK = 0x8030 case TABLE_TOO_LARGE = 0x8031 case BLEND_EQUATION = 0x8009 case MIN = 0x8007 case MAX = 0x8008 case FUNC_ADD = 0x8006 case FUNC_SUBTRACT = 0x800A case FUNC_REVERSE_SUBTRACT = 0x800B case BLEND_COLOR = 0x8005 // OpenGL 1.3 case TEXTURE0 = 0x84C0 case TEXTURE1 = 0x84C1 case TEXTURE2 = 0x84C2 case TEXTURE3 = 0x84C3 case TEXTURE4 = 0x84C4 case TEXTURE5 = 0x84C5 case TEXTURE6 = 0x84C6 case TEXTURE7 = 0x84C7 case TEXTURE8 = 0x84C8 case TEXTURE9 = 0x84C9 case TEXTURE10 = 0x84CA case TEXTURE11 = 0x84CB case TEXTURE12 = 0x84CC case TEXTURE13 = 0x84CD case TEXTURE14 = 0x84CE case TEXTURE15 = 0x84CF case TEXTURE16 = 0x84D0 case TEXTURE17 = 0x84D1 case TEXTURE18 = 0x84D2 case TEXTURE19 = 0x84D3 case TEXTURE20 = 0x84D4 case TEXTURE21 = 0x84D5 case TEXTURE22 = 0x84D6 case TEXTURE23 = 0x84D7 case TEXTURE24 = 0x84D8 case TEXTURE25 = 0x84D9 case TEXTURE26 = 0x84DA case TEXTURE27 = 0x84DB case TEXTURE28 = 0x84DC case TEXTURE29 = 0x84DD case TEXTURE30 = 0x84DE case TEXTURE31 = 0x84DF case ACTIVE_TEXTURE = 0x84E0 case CLIENT_ACTIVE_TEXTURE = 0x84E1 case MAX_TEXTURE_UNITS = 0x84E2 case NORMAL_MAP = 0x8511 case REFLECTION_MAP = 0x8512 case TEXTURE_CUBE_MAP = 0x8513 case TEXTURE_BINDING_CUBE_MAP = 0x8514 case TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515 case TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516 case TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517 case TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518 case TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519 case TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A case PROXY_TEXTURE_CUBE_MAP = 0x851B case MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C case COMPRESSED_ALPHA = 0x84E9 case COMPRESSED_LUMINANCE = 0x84EA case COMPRESSED_LUMINANCE_ALPHA = 0x84EB case COMPRESSED_INTENSITY = 0x84EC case COMPRESSED_RGB = 0x84ED case COMPRESSED_RGBA = 0x84EE case TEXTURE_COMPRESSION_HINT = 0x84EF case TEXTURE_COMPRESSED_IMAGE_SIZE = 0x86A0 case TEXTURE_COMPRESSED = 0x86A1 case NUM_COMPRESSED_TEXTURE_FORMATS = 0x86A2 case COMPRESSED_TEXTURE_FORMATS = 0x86A3 case MULTISAMPLE = 0x809D case SAMPLE_ALPHA_TO_COVERAGE = 0x809E case SAMPLE_ALPHA_TO_ONE = 0x809F case SAMPLE_COVERAGE = 0x80A0 case SAMPLE_BUFFERS = 0x80A8 case SAMPLES = 0x80A9 case SAMPLE_COVERAGE_VALUE = 0x80AA case SAMPLE_COVERAGE_INVERT = 0x80AB case MULTISAMPLE_BIT = 0x20000000 case TRANSPOSE_MODELVIEW_MATRIX = 0x84E3 case TRANSPOSE_PROJECTION_MATRIX = 0x84E4 case TRANSPOSE_TEXTURE_MATRIX = 0x84E5 case TRANSPOSE_COLOR_MATRIX = 0x84E6 case COMBINE = 0x8570 case COMBINE_RGB = 0x8571 case COMBINE_ALPHA = 0x8572 case SOURCE0_RGB = 0x8580 case SOURCE1_RGB = 0x8581 case SOURCE2_RGB = 0x8582 case SOURCE0_ALPHA = 0x8588 case SOURCE1_ALPHA = 0x8589 case SOURCE2_ALPHA = 0x858A case OPERAND0_RGB = 0x8590 case OPERAND1_RGB = 0x8591 case OPERAND2_RGB = 0x8592 case OPERAND0_ALPHA = 0x8598 case OPERAND1_ALPHA = 0x8599 case OPERAND2_ALPHA = 0x859A case RGB_SCALE = 0x8573 case ADD_SIGNED = 0x8574 case INTERPOLATE = 0x8575 case SUBTRACT = 0x84E7 case NT = 0x8576 case PRIMARY_COLOR = 0x8577 case PREVIOUS = 0x8578 case DOT3_RGB = 0x86AE case DOT3_RGBA = 0x86AF case CLAMP_TO_BORDER = 0x812D // GL_ARB_multitexture (ARB extension 1 and OpenGL 1.2.1) case ARB_multitexture = 1 case TEXTURE0_ARB = 0x84C0 case TEXTURE1_ARB = 0x84C1 case TEXTURE2_ARB = 0x84C2 case TEXTURE3_ARB = 0x84C3 case TEXTURE4_ARB = 0x84C4 case TEXTURE5_ARB = 0x84C5 case TEXTURE6_ARB = 0x84C6 case TEXTURE7_ARB = 0x84C7 case TEXTURE8_ARB = 0x84C8 case TEXTURE9_ARB = 0x84C9 case TEXTURE10_ARB = 0x84CA case TEXTURE11_ARB = 0x84CB case TEXTURE12_ARB = 0x84CC case TEXTURE13_ARB = 0x84CD case TEXTURE14_ARB = 0x84CE case TEXTURE15_ARB = 0x84CF case TEXTURE16_ARB = 0x84D0 case TEXTURE17_ARB = 0x84D1 case TEXTURE18_ARB = 0x84D2 case TEXTURE19_ARB = 0x84D3 case TEXTURE20_ARB = 0x84D4 case TEXTURE21_ARB = 0x84D5 case TEXTURE22_ARB = 0x84D6 case TEXTURE23_ARB = 0x84D7 case TEXTURE24_ARB = 0x84D8 case TEXTURE25_ARB = 0x84D9 case TEXTURE26_ARB = 0x84DA case TEXTURE27_ARB = 0x84DB case TEXTURE28_ARB = 0x84DC case TEXTURE29_ARB = 0x84DD case TEXTURE30_ARB = 0x84DE case TEXTURE31_ARB = 0x84DF case ACTIVE_TEXTURE_ARB = 0x84E0 case CLIENT_ACTIVE_TEXTURE_ARB = 0x84E1 case MAX_TEXTURE_UNITS_ARB = 0x84E2 } // glu public ffi fn gluPerspective(fovy: f64, aspect: f64, znear: f64, zfar: f64) -> void public ffi fn glClearIndex(c: f32) -> void public ffi fn glClearColor(red: f32, green: f32, blue: f32, alpha: f32) -> void public ffi fn glClear(mask: GL) -> void public ffi fn glIndexMask(mask: u32) -> void public ffi fn glColorMask(red: bool, green: bool, blue: bool, alpha: bool) -> void public ffi fn glAlphaFunc(f: u32, ref: f32) -> void public ffi fn glBlendFunc(sfactor: u32, dfactor: u32) -> void public ffi fn glLogicOp(opcode: u32) -> void public ffi fn glCullFace(mode: u32) -> void public ffi fn glFrontFace(mode: u32) -> void public ffi fn glPointSize(size: f32) -> void public ffi fn glLineWidth(width: f32) -> void public ffi fn glLineStipple(factor: i32, pattern: u16) -> void public ffi fn glPolygonMode(face: u32, mode: u32) -> void public ffi fn glPolygonOffset(factor: f32, units: f32) -> void public ffi fn glPolygonStipple(mask: &i8) -> void public ffi fn glGetPolygonStipple(mask: &i8) -> void public ffi fn glEdgeFlag(flag: bool) -> void public ffi fn glEdgeFlagv(flag: &bool) -> void public ffi fn glScissor(x: i32, y: i32, width: i32, height: i32) -> void public ffi fn glClipPlane(plane: u32, equation: &f64) -> void public ffi fn glGetClipPlane(plane: u32, equation: &f64) -> void public ffi fn glDrawBuffer(mode: u32) -> void public ffi fn glReadBuffer(mode: u32) -> void public ffi fn glEnable(cap: GL) -> void public ffi fn glDisable(cap: GL) -> void public ffi fn glIsEnabled(cap: u32) -> bool public ffi fn glEnableClientState(cap: GL) -> void public ffi fn glDisableClientState(cap: GL) -> void public ffi fn glGetBooleanv(pname: u32, params: &bool) -> void public ffi fn glGetDoublev(pname: u32, params: &f64) -> void public ffi fn glGetFloatv(pname: u32, params: &f32) -> void public ffi fn glGetIntegerv(pname: u32, params: &i32) -> void public ffi fn glPushAttrib(mask: u32) -> void public ffi fn glPopAttrib() -> void public ffi fn glPushClientAttrib(mask: u32) -> void public ffi fn glPopClientAttrib() -> void public ffi fn glRenderMode(mode: u32) -> i32 public ffi fn glGetError() -> u32 public ffi fn glGetString(name: u32) -> &i8 public ffi fn glFinish() -> void public ffi fn glFlush() -> void public ffi fn glHint(target: u32, mode: u32) -> void // Depth Buffer public ffi fn glClearDepth(depth: f64) -> void public ffi fn glDepthFunc(f: GL) -> void public ffi fn glDepthMask(flag: bool) -> void public ffi fn glDepthRange(near_val: f64, far_val: f64) -> void // Accumulation Buffer public ffi fn glClearAccum(red: f32, green: f32, blue: f32, alpha: f32) -> void public ffi fn glAccum(op: u32, value: f32) -> void // Transformation public ffi fn glMatrixMode(mode: GL) -> void public ffi fn glOrtho(left: f64, right: f64, bottom: f64, top: f64, near_val: f64, far_val: f64) -> void public ffi fn glFrustum(left: f64, right: f64, bottom: f64, top: f64, near_val: f64, far_val: f64) -> void public ffi fn glViewport(x: i32, y: i32, width: i32, height: i32) -> void public ffi fn glPushMatrix() -> void public ffi fn glPopMatrix() -> void public ffi fn glLoadIdentity() -> void public ffi fn glLoadMatrixd(m: &f64) -> void public ffi fn glLoadMatrixf(m: &f32) -> void public ffi fn glMultMatrixd(m: &f64) -> void public ffi fn glMultMatrixf(m: &f32) -> void public ffi fn glRotated(angle: f64, x: f64, y: f64, z: f64) -> void public ffi fn glRotatef(angle: f32, x: f32, y: f32, z: f32) -> void public ffi fn glScaled(x: f64, y: f64, z: f64) -> void public ffi fn glScalef(x: f32, y: f32, z: f32) -> void public ffi fn glTranslated(x: f64, y: f64, z: f64) -> void public ffi fn glTranslatef(x: f32, y: f32, z: f32) -> void // Display Lists public ffi fn glIsList(list: u32) -> bool public ffi fn glDeleteLists(list: u32, range: i32) -> void public ffi fn glGenLists(range: i32) -> u32 public ffi fn glNewList(list: u32, mode: u32) -> void public ffi fn glEndList() -> void public ffi fn glCallList(list: u32) -> void public ffi fn glCallLists(n: i32, type: u32, lists: &void) -> void public ffi fn glListBase(base: u32) -> void // Drawing Functions public ffi fn glBegin(mode: GL) -> void public ffi fn glEnd() -> void public ffi fn glVertex2d(x: f64, y: f64) -> void public ffi fn glVertex2f(x: f32, y: f32) -> void public ffi fn glVertex2i(x: i32, y: i32) -> void public ffi fn glVertex2s(x: i16, y: i16) -> void public ffi fn glVertex3d(x: f64, y: f64, z: f64) -> void public ffi fn glVertex3f(x: f32, y: f32, z: f32) -> void public ffi fn glVertex3i(x: i32, y: i32, z: i32) -> void public ffi fn glVertex3s(x: i16, y: i16, z: i16) -> void public ffi fn glVertex4d(x: f64, y: f64, z: f64, w: f64) -> void public ffi fn glVertex4f(x: f32, y: f32, z: f32, w: f32) -> void public ffi fn glVertex4i(x: i32, y: i32, z: i32, w: i32) -> void public ffi fn glVertex4s(x: i16, y: i16, z: i16, w: i16) -> void public ffi fn glVertex2dv(v: &f64) -> void public ffi fn glVertex2fv(v: &f32) -> void public ffi fn glVertex2iv(v: &i32) -> void public ffi fn glVertex2sv(v: &i16) -> void public ffi fn glVertex3dv(v: &f64) -> void public ffi fn glVertex3fv(v: &f32) -> void public ffi fn glVertex3iv(v: &i32) -> void public ffi fn glVertex3sv(v: &i16) -> void public ffi fn glVertex4dv(v: &f64) -> void public ffi fn glVertex4fv(v: &f32) -> void public ffi fn glVertex4iv(v: &i32) -> void public ffi fn glVertex4sv(v: &i16) -> void public ffi fn glNormal3b(nx: i8, ny: i8, nz: i8) -> void public ffi fn glNormal3d(nx: f64, ny: f64, nz: f64) -> void public ffi fn glNormal3f(nx: f32, ny: f32, nz: f32) -> void public ffi fn glNormal3i(nx: i32, ny: i32, nz: i32) -> void public ffi fn glNormal3s(nx: i16, ny: i16, nz: i16) -> void public ffi fn glNormal3bv(v: &i8) -> void public ffi fn glNormal3dv(v: &f64) -> void public ffi fn glNormal3fv(v: &f32) -> void public ffi fn glNormal3iv(v: &i32) -> void public ffi fn glNormal3sv(v: &i16) -> void public ffi fn glIndexd(c: f64) -> void public ffi fn glIndexf(c: f32) -> void public ffi fn glIndexi(c: i32) -> void public ffi fn glIndexs(c: i16) -> void public ffi fn glIndexub(c: i8) -> void public ffi fn glIndexdv(c: &f64) -> void public ffi fn glIndexfv(c: &f32) -> void public ffi fn glIndexiv(c: &i32) -> void public ffi fn glIndexsv(c: &i16) -> void public ffi fn glIndexubv(c: &i8) -> void public ffi fn glColor3b(red: i8, green: i8, blue: i8) -> void public ffi fn glColor3d(red: f64, green: f64, blue: f64) -> void public ffi fn glColor3f(red: f32, green: f32, blue: f32) -> void public ffi fn glColor3i(red: i32, green: i32, blue: i32) -> void public ffi fn glColor3s(red: i16, green: i16, blue: i16) -> void public ffi fn glColor3ub(red: i8, green: i8, blue: i8) -> void public ffi fn glColor3ui(red: u32, green: u32, blue: u32) -> void public ffi fn glColor3us(red: u16, green: u16, blue: u16) -> void public ffi fn glColor4b(red: i8, green: i8, blue: i8, alpha: i8) -> void public ffi fn glColor4d(red: f64, green: f64, blue: f64, alpha: f64) -> void public ffi fn glColor4f(red: f32, green: f32, blue: f32, alpha: f32) -> void public ffi fn glColor4i(red: i32, green: i32, blue: i32, alpha: i32) -> void public ffi fn glColor4s(red: i16, green: i16, blue: i16, alpha: i16) -> void public ffi fn glColor4ub(red: i8, green: i8, blue: i8, alpha: i8) -> void public ffi fn glColor4ui(red: u32, green: u32, blue: u32, alpha: u32) -> void public ffi fn glColor4us(red: u16, green: u16, blue: u16, alpha: u16) -> void public ffi fn glColor3bv(v: &i8) -> void public ffi fn glColor3dv(v: &f64) -> void public ffi fn glColor3fv(v: &f32) -> void public ffi fn glColor3iv(v: &i32) -> void public ffi fn glColor3sv(v: &i16) -> void public ffi fn glColor3ubv(v: &i8) -> void public ffi fn glColor3uiv(v: &u32) -> void public ffi fn glColor3usv(v: &u16) -> void public ffi fn glColor4bv(v: &i8) -> void public ffi fn glColor4dv(v: &f64) -> void public ffi fn glColor4fv(v: &f32) -> void public ffi fn glColor4iv(v: &i32) -> void public ffi fn glColor4sv(v: &i16) -> void public ffi fn glColor4ubv(v: &i8) -> void public ffi fn glColor4uiv(v: &u32) -> void public ffi fn glColor4usv(v: &u16) -> void public ffi fn glTexCoord1d(s: f64) -> void public ffi fn glTexCoord1f(s: f32) -> void public ffi fn glTexCoord1i(s: i32) -> void public ffi fn glTexCoord1s(s: i16) -> void public ffi fn glTexCoord2d(s: f64, t: f64) -> void public ffi fn glTexCoord2f(s: f32, t: f32) -> void public ffi fn glTexCoord2i(s: i32, t: i32) -> void public ffi fn glTexCoord2s(s: i16, t: i16) -> void public ffi fn glTexCoord3d(s: f64, t: f64, r: f64) -> void public ffi fn glTexCoord3f(s: f32, t: f32, r: f32) -> void public ffi fn glTexCoord3i(s: i32, t: i32, r: i32) -> void public ffi fn glTexCoord3s(s: i16, t: i16, r: i16) -> void public ffi fn glTexCoord4d(s: f64, t: f64, r: f64, q: f64) -> void public ffi fn glTexCoord4f(s: f32, t: f32, r: f32, q: f32) -> void public ffi fn glTexCoord4i(s: i32, t: i32, r: i32, q: i32) -> void public ffi fn glTexCoord4s(s: i16, t: i16, r: i16, q: i16) -> void public ffi fn glTexCoord1dv(v: &f64) -> void public ffi fn glTexCoord1fv(v: &f32) -> void public ffi fn glTexCoord1iv(v: &i32) -> void public ffi fn glTexCoord1sv(v: &i16) -> void public ffi fn glTexCoord2dv(v: &f64) -> void public ffi fn glTexCoord2fv(v: &f32) -> void public ffi fn glTexCoord2iv(v: &i32) -> void public ffi fn glTexCoord2sv(v: &i16) -> void public ffi fn glTexCoord3dv(v: &f64) -> void public ffi fn glTexCoord3fv(v: &f32) -> void public ffi fn glTexCoord3iv(v: &i32) -> void public ffi fn glTexCoord3sv(v: &i16) -> void public ffi fn glTexCoord4dv(v: &f64) -> void public ffi fn glTexCoord4fv(v: &f32) -> void public ffi fn glTexCoord4iv(v: &i32) -> void public ffi fn glTexCoord4sv(v: &i16) -> void public ffi fn glRasterPos2d(x: f64, y: f64) -> void public ffi fn glRasterPos2f(x: f32, y: f32) -> void public ffi fn glRasterPos2i(x: i32, y: i32) -> void public ffi fn glRasterPos2s(x: i16, y: i16) -> void public ffi fn glRasterPos3d(x: f64, y: f64, z: f64) -> void public ffi fn glRasterPos3f(x: f32, y: f32, z: f32) -> void public ffi fn glRasterPos3i(x: i32, y: i32, z: i32) -> void public ffi fn glRasterPos3s(x: i16, y: i16, z: i16) -> void public ffi fn glRasterPos4d(x: f64, y: f64, z: f64, w: f64) -> void public ffi fn glRasterPos4f(x: f32, y: f32, z: f32, w: f32) -> void public ffi fn glRasterPos4i(x: i32, y: i32, z: i32, w: i32) -> void public ffi fn glRasterPos4s(x: i16, y: i16, z: i16, w: i16) -> void public ffi fn glRasterPos2dv(v: &f64) -> void public ffi fn glRasterPos2fv(v: &f32) -> void public ffi fn glRasterPos2iv(v: &i32) -> void public ffi fn glRasterPos2sv(v: &i16) -> void public ffi fn glRasterPos3dv(v: &f64) -> void public ffi fn glRasterPos3fv(v: &f32) -> void public ffi fn glRasterPos3iv(v: &i32) -> void public ffi fn glRasterPos3sv(v: &i16) -> void public ffi fn glRasterPos4dv(v: &f64) -> void public ffi fn glRasterPos4fv(v: &f32) -> void public ffi fn glRasterPos4iv(v: &i32) -> void public ffi fn glRasterPos4sv(v: &i16) -> void public ffi fn glRectd(x1: f64, y1: f64, x2: f64, y2: f64) -> void public ffi fn glRectf(x1: f32, y1: f32, x2: f32, y2: f32) -> void public ffi fn glRecti(x1: i32, y1: i32, x2: i32, y2: i32) -> void public ffi fn glRects(x1: i16, y1: i16, x2: i16, y2: i16) -> void public ffi fn glRectdv(v1: &f64, v2: &f64) -> void public ffi fn glRectfv(v1: &f32, v2: &f32) -> void public ffi fn glRectiv(v1: &i32, v2: &i32) -> void public ffi fn glRectsv(v1: &i16, v2: &i16) -> void // Vertex Arrays public ffi fn glVertexPointer(size: i32, type: GL, stride: i32, ptr: &void) -> void public ffi fn glNormalPointer(type: GL, stride: i32, ptr: &void) -> void public ffi fn glColorPointer(size: i32, type: GL, stride: i32, ptr: &void) -> void public ffi fn glIndexPointer(type: GL, stride: i32, ptr: &void) -> void public ffi fn glTexCoordPointer(size: i32, type: GL, stride: i32, ptr: &void) -> void public ffi fn glEdgeFlagPointer(stride: i32, ptr: &void) -> void public ffi fn glGetPointerv(pname: u32, params: &&void) -> void public ffi fn glArrayElement(i: i32) -> void public ffi fn glDrawArrays(mode: GL, first: i32, count: i32) -> void public ffi fn glDrawElements(mode: GL, count: i32, type: GL, indices: &void) -> void public ffi fn glInterleavedArrays(format: u32, stride: i32, pointer: &void) -> void // Lighting public ffi fn glShadeModel(mode: u32) -> void public ffi fn glLightf(light: u32, pname: u32, param: f32) -> void public ffi fn glLighti(light: u32, pname: u32, param: i32) -> void public ffi fn glLightfv(light: u32, pname: u32, params: &f32) -> void public ffi fn glLightiv(light: u32, pname: u32, params: &i32) -> void public ffi fn glGetLightfv(light: u32, pname: u32, params: &f32) -> void public ffi fn glGetLightiv(light: u32, pname: u32, params: &i32) -> void public ffi fn glLightModelf(pname: u32, param: f32) -> void public ffi fn glLightModeli(pname: u32, param: i32) -> void public ffi fn glLightModelfv(pname: u32, params: &f32) -> void public ffi fn glLightModeliv(pname: u32, params: &i32) -> void public ffi fn glMaterialf(face: u32, pname: u32, param: f32) -> void public ffi fn glMateriali(face: u32, pname: u32, param: i32) -> void public ffi fn glMaterialfv(face: u32, pname: u32, params: &f32) -> void public ffi fn glMaterialiv(face: u32, pname: u32, params: &i32) -> void public ffi fn glGetMaterialfv(face: u32, pname: u32, params: &f32) -> void public ffi fn glGetMaterialiv(face: u32, pname: u32, params: &i32) -> void public ffi fn glColorMaterial(face: u32, mode: u32) -> void // Raster Functions public ffi fn glPixelZoom(xfactor: f32, yfactor: f32) -> void public ffi fn glPixelStoref(pname: u32, param: f32) -> void public ffi fn glPixelStorei(pname: u32, param: i32) -> void public ffi fn glPixelTransferf(pname: u32, param: f32) -> void public ffi fn glPixelTransferi(pname: u32, param: i32) -> void public ffi fn glPixelMapfv(map: u32, mapsize: i32, values: &f32) -> void public ffi fn glPixelMapuiv(map: u32, mapsize: i32, values: &u32) -> void public ffi fn glPixelMapusv(map: u32, mapsize: i32, values: &u16) -> void public ffi fn glGetPixelMapfv(map: u32, values: &f32) -> void public ffi fn glGetPixelMapuiv(map: u32, values: &u32) -> void public ffi fn glGetPixelMapusv(map: u32, values: &u16) -> void public ffi fn glBitmap(width: i32, height: i32, xorig: f32, yorig: f32, xmove: f32, ymove: f32, bitmap: &i8) -> void public ffi fn glReadPixels(x: i32, y: i32, width: i32, height: i32, format: u32, type: u32, pixels: &void) -> void public ffi fn glDrawPixels(width: i32, height: i32, format: u32, type: u32, pixels: &void) -> void public ffi fn glCopyPixels(x: i32, y: i32, width: i32, height: i32, type: u32) -> void // Stenciling public ffi fn glStencilFunc(f: u32, ref: i32, mask: u32) -> void public ffi fn glStencilMask(mask: u32) -> void public ffi fn glStencilOp(fail: u32, zfail: u32, zpass: u32) -> void public ffi fn glClearStencil(s: i32) -> void // Texture Mapping public ffi fn glTexGend(coord: u32, pname: u32, param: f64) -> void public ffi fn glTexGenf(coord: u32, pname: u32, param: f32) -> void public ffi fn glTexGeni(coord: u32, pname: u32, param: i32) -> void public ffi fn glTexGendv(coord: u32, pname: u32, params: f64) -> void public ffi fn glTexGenfv(coord: u32, pname: u32, params: f32) -> void public ffi fn glTexGeniv(coord: u32, pname: u32, params: i32) -> void public ffi fn glGetTexGendv(coord: u32, pname: u32, params: f64) -> void public ffi fn glGetTexGenfv(coord: u32, pname: u32, params: f32) -> void public ffi fn glGetTexGeniv(coord: u32, pname: u32, params: i32) -> void public ffi fn glTexEnvf(target: u32, pname: u32, param: f32) -> void public ffi fn glTexEnvi(target: u32, pname: u32, param: i32) -> void public ffi fn glTexEnvfv(target: u32, pname: u32, params: f32) -> void public ffi fn glTexEnviv(target: u32, pname: u32, params: i32) -> void public ffi fn glGetTexEnvfv(target: u32, pname: u32, params: f32) -> void public ffi fn glGetTexEnviv(target: u32, pname: u32, params: i32) -> void public ffi fn glTexParameterf(target: u32, pname: u32, param: f32) -> void public ffi fn glTexParameteri(target: u32, pname: u32, param: i32) -> void public ffi fn glTexParameterfv(target: u32, pname: u32, params: f32) -> void public ffi fn glTexParameteriv(target: u32, pname: u32, params: i32) -> void public ffi fn glGetTexParameterfv(target: u32, pname: u32, params: f32) -> void public ffi fn glGetTexParameteriv(target: u32, pname: u32, params: i32) -> void public ffi fn glGetTexLevelParameterfv(target: u32, level: i32, pname: u32, params: &f32) -> void public ffi fn glGetTexLevelParameteriv(target: u32, level: i32, pname: u32, params: &i32) -> void public ffi fn glTexImage1D(target: u32, level: i32, internalFormat: i32, width: i32, border: i32, format: u32, type: u32, pixels: &void) -> void public ffi fn glTexImage2D(target: u32, level: i32, internalFormat: i32, width: i32, height: i32, border: i32, format: u32, type: u32, pixels: &void) -> void public ffi fn glGetTexImage(target: u32, level: i32, format: u32, type: u32, pixels: &void) -> void // OpenGL 1.1 functions public ffi fn glGenTextures(n: i32, textures: &u32) -> void public ffi fn glDeleteTextures(n: i32, textures: &u32) -> void public ffi fn glBindTexture(target: u32, texture: u32) -> void public ffi fn glPrioritizeTextures(n: i32, textures: &u32, priorities: &f32) -> void public ffi fn glAreTexturesResident(n: i32, textures: &u32, residences: &bool) -> bool public ffi fn glIsTexture(texture: u32) -> bool public ffi fn glTexSubImage1D(target: u32, level: i32, xoffset: i32, width: i32, format: u32, type: u32, pixels: &void) -> void public ffi fn glTexSubImage2D(target: u32, level: i32, xoffset: i32, yoffset: i32, width: i32, height: i32, format: u32, type: u32, pixels: &void) -> void public ffi fn glCopyTexImage1D(target: u32, level: i32, internalformat: u32, x: i32, y: i32, width: i32, border: i32) -> void public ffi fn glCopyTexImage2D(target: u32, level: i32, internalformat: u32, x: i32, y: i32, width: i32, height: i32, border: i32) -> void public ffi fn glCopyTexSubImage1D(target: u32, level: i32, xoffset: i32, x: i32, y: i32, width: i32) -> void public ffi fn glCopyTexSubImage2D(target: u32, level: i32, xoffset: i32, yoffset: i32, x: i32, y: i32, width: i32, height: i32) -> void // Evaluators public ffi fn glMap1d(target: u32, u1: f64, u2: f64, stride: i32, order: i32, points: &f64) -> void public ffi fn glMap1f(target: u32, u1: f32, u2: f32, stride: i32, order: i32, points: &f32) -> void public ffi fn glMap2d(target: u32, u1: f64, u2: f64, ustride: i32, uorder: i32, v1: f64, v2: f64, vstride: i32, vorder: i32, points: &f64) -> void public ffi fn glMap2f(target: u32, u1: f32, u2: f32, ustride: i32, uorder: i32, v1: f32, v2: f32, vstride: i32, vorder: i32, points: &f32) -> void public ffi fn glGetMapdv(target: u32, query: u32, v: &f64) -> void public ffi fn glGetMapfv(target: u32, query: u32, v: &f32) -> void public ffi fn glGetMapiv(target: u32, query: u32, v: &i32) -> void public ffi fn glEvalCoord1d(u: f64) -> void public ffi fn glEvalCoord1f(u: f32) -> void public ffi fn glEvalCoord1dv(u: &f64) -> void public ffi fn glEvalCoord1fv(u: &f32) -> void public ffi fn glEvalCoord2d(u: f64, v: f64) -> void public ffi fn glEvalCoord2f(u: f32, v: f32) -> void public ffi fn glEvalCoord2dv(u: &f64) -> void public ffi fn glEvalCoord2fv(u: &f32) -> void public ffi fn glMapGrid1d(un: i32, u1: f64, u2: f64) -> void public ffi fn glMapGrid1f(un: i32, u1: f32, u2: f32) -> void public ffi fn glMapGrid2d(un: i32, u1: f64, u2: f64, vn: i32, v1: f64, v2: f64) -> void public ffi fn glMapGrid2f(un: i32, u1: f32, u2: f32, vn: i32, v1: f32, v2: f32) -> void public ffi fn glEvalPoint1(i: i32) -> void public ffi fn glEvalPoint2(i: i32, j: i32) -> void public ffi fn glEvalMesh1(mode: u32, i1: i32, i2: i32) -> void public ffi fn glEvalMesh2(mode: u32, i1: i32, i2: i32, j1: i32, j2: i32) -> void // Fog public ffi fn glFogf(pname: u32, param: f32) -> void public ffi fn glFogi(pname: u32, param: i32) -> void public ffi fn glFogfv(pname: u32, params: &f32) -> void public ffi fn glFogiv(pname: u32, params: &i32) -> void // Selection and Feedback public ffi fn glFeedbackBuffer(size: i32, type: u32, buffer: &f32) -> void public ffi fn glPassThrough(token: f32) -> void public ffi fn glSelectBuffer(size: i32, buffer: &u32) -> void public ffi fn glInitNames() -> void public ffi fn glLoadName(name: u32) -> void public ffi fn glPushName(name: u32) -> void public ffi fn glPopName() -> void public ffi fn glDrawRangeElements(mode: u32, start: u32, end: u32, count: i32, type: u32, indices: &void) -> void public ffi fn glTexImage3D(target: u32, level: i32, internalFormat: i32, width: i32, height: i32, depth: i32, border: i32, format: u32, type: u32, pixels: &void) -> void public ffi fn glTexSubImage3D(target: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, format: u32, type: u32, pixels: &void) -> void public ffi fn glCopyTexSubImage3D(target: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, x: i32, y: i32, width: i32, height: i32) -> void public ffi fn glColorTable(target: u32, internalformat: u32, width: i32, format: u32, type: u32, table: &void) -> void public ffi fn glColorSubTable(target: u32, start: i32, count: i32, format: u32, type: u32, data: &void) -> void public ffi fn glColorTableParameteriv(target: u32, pname: u32, params: &i32) -> void public ffi fn glColorTableParameterfv(target: u32, pname: u32, params: &f32) -> void public ffi fn glCopyColorSubTable(target: u32, start: i32, x: i32, y: i32, width: i32) -> void public ffi fn glCopyColorTable(target: u32, internalformat: u32, x: i32, y: i32, width: i32) -> void public ffi fn glGetColorTable(target: u32, format: u32, type: u32, table: &void) -> void public ffi fn glGetColorTableParameterfv(target: u32, pname: u32, params: &f32) -> void public ffi fn glGetColorTableParameteriv(target: u32, pname: u32, params: &i32) -> void public ffi fn glBlendEquation(mode: u32) -> void public ffi fn glBlendColor(red: f32, green: f32, blue: f32, alpha: f32) -> void public ffi fn glHistogram(target: u32, width: i32, internalformat: u32, sink: bool) -> void public ffi fn glResetHistogram(target: u32) -> void public ffi fn glGetHistogram(target: u32, reset: bool, format: u32, type: u32, values: &void) -> void public ffi fn glGetHistogramParameterfv(target: u32, pname: u32, params: &f32) -> void public ffi fn glGetHistogramParameteriv(target: u32, pname: u32, params: &i32) -> void public ffi fn glMinmax(target: u32, internalformat: u32, sink: bool) -> void public ffi fn glResetMinmax(target: u32) -> void public ffi fn glGetMinmax(target: u32, reset: bool, format: u32, types: u32, values: &void) -> void public ffi fn glGetMinmaxParameterfv(target: u32, pname: u32, params: &f32) -> void public ffi fn glGetMinmaxParameteriv(target: u32, pname: u32, params: &i32) -> void public ffi fn glConvolutionFilter1D(target: u32, internalformat: u32, width: i32, format: u32, type: u32, image: &void) -> void public ffi fn glConvolutionFilter2D(target: u32, internalformat: u32, width: i32, height: i32, format: u32, type: u32, image: &void) -> void public ffi fn glConvolutionParameterf(target: u32, pname: u32, params: f32) -> void public ffi fn glConvolutionParameterfv(target: u32, pname: u32, params: &f32) -> void public ffi fn glConvolutionParameteri(target: u32, pname: u32, params: i32) -> void public ffi fn glConvolutionParameteriv(target: u32, pname: u32, params: &i32) -> void public ffi fn glCopyConvolutionFilter1D(target: u32, internalformat: u32, x: i32, y: i32, width: i32) -> void public ffi fn glCopyConvolutionFilter2D(target: u32, internalformat: u32, x: i32, y: i32, width: i32, height: i32) -> void public ffi fn glGetConvolutionFilter(target: u32, format: u32, type: u32, image: &void) -> void public ffi fn glGetConvolutionParameterfv(target: u32, pname: u32, params: &f32) -> void public ffi fn glGetConvolutionParameteriv(target: u32, pname: u32, params: &i32) -> void public ffi fn glSeparableFilter2D(target: u32, internalformat: u32, width: i32, height: i32, format: u32, type: u32, row: &void, column: &void) -> void public ffi fn glGetSeparableFilter(target: u32, format: u32, type: u32, row: &void, column: &void, span: &void) -> void public ffi fn glActiveTexture(texture: u32) -> void public ffi fn glClientActiveTexture(texture: u32) -> void public ffi fn glCompressedTexImage1D(target: u32, level: i32, internalformat: u32, width: i32, border: i32, imageSize: i32, data: &void) -> void public ffi fn glCompressedTexImage2D(target: u32, level: i32, internalformat: u32, width: i32, height: i32, border: i32, imageSize: i32, data: &void) -> void public ffi fn glCompressedTexImage3D(target: u32, level: i32, internalformat: u32, width: i32, height: i32, voiddepth: i32, border: i32, imageSize: i32, data: &void) public ffi fn glCompressedTexSubImage1D(target: u32, level: i32, xoffset: i32, width: i32, format: u32, imageSize: i32, data: &void) -> void public ffi fn glCompressedTexSubImage2D(target: u32, level: i32, xoffset: i32, yoffset: i32, width: i32, height: i32, format: u32, imageSize: i32, data: &void) -> void public ffi fn glCompressedTexSubImage3D(target: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, format: u32, imageSize: i32, data: &void) -> void public ffi fn glGetCompressedTexImage(target: u32, lod: i32, img: &void) -> void public ffi fn glMultiTexCoord1d(target: u32, s: f64) -> void public ffi fn glMultiTexCoord1dv(target: u32, v: &f64) -> void public ffi fn glMultiTexCoord1f(target: u32, s: f32) -> void public ffi fn glMultiTexCoord1fv(target: u32, v: &f32) -> void public ffi fn glMultiTexCoord1i(target: u32, s: i32) -> void public ffi fn glMultiTexCoord1iv(target: u32, v: &i32) -> void public ffi fn glMultiTexCoord1s(target: u32, s: i16) -> void public ffi fn glMultiTexCoord1sv(target: u32, v: &i16) -> void public ffi fn glMultiTexCoord2d(target: u32, s: f64, t: f64) -> void public ffi fn glMultiTexCoord2dv(target: u32, v: &f64) -> void public ffi fn glMultiTexCoord2f(target: u32, s: f32, t: f32) -> void public ffi fn glMultiTexCoord2fv(target: u32, v: &f32) -> void public ffi fn glMultiTexCoord2i(target: u32, s: i32, t: i32) -> void public ffi fn glMultiTexCoord2iv(target: u32, v: &i32) -> void public ffi fn glMultiTexCoord2s(target: u32, s: i16, t: i16) -> void public ffi fn glMultiTexCoord2sv(target: u32, v: &i16) -> void public ffi fn glMultiTexCoord3d(target: u32, s: f64, t: f64, r: f64) -> void public ffi fn glMultiTexCoord3dv(target: u32, v: &f64) -> void public ffi fn glMultiTexCoord3f(target: u32, s: f32, t: f32, r: f32) -> void public ffi fn glMultiTexCoord3fv(target: u32, v: &f32) -> void public ffi fn glMultiTexCoord3i(target: u32, s: i32, t: i32, r: i32) -> void public ffi fn glMultiTexCoord3iv(target: u32, v: &i32) -> void public ffi fn glMultiTexCoord3s(target: u32, s: i16, t: i16, r: i16) -> void public ffi fn glMultiTexCoord3sv(target: u32, v: &i16) -> void public ffi fn glMultiTexCoord4d(target: u32, s: f64, t: f64, r: f64, q: f64) -> void public ffi fn glMultiTexCoord4dv(target: u32, v: &f64) -> void public ffi fn glMultiTexCoord4f(target: u32, s: f32, t: f32, r: f32, q: f32) -> void public ffi fn glMultiTexCoord4fv(target: u32, v: &f32) -> void public ffi fn glMultiTexCoord4i(target: u32, s: i32, t: i32, r: i32, q: i32) -> void public ffi fn glMultiTexCoord4iv(target: u32, v: &i32) -> void public ffi fn glMultiTexCoord4s(target: u32, s: i16, t: i16, r: i16, q: i16) -> void public ffi fn glMultiTexCoord4sv(target: u32, v: &i16) -> void public ffi fn glLoadTransposeMatrixd(m: [f64: 16]) -> void public ffi fn glLoadTransposeMatrixf(m: [f32: 16]) -> void public ffi fn glMultTransposeMatrixd(m: [f64: 16]) -> void public ffi fn glMultTransposeMatrixf(m: [f32: 16]) -> void public ffi fn glSampleCoverage(value: f32, invert: bool) -> void public ffi fn glActiveTextureARB(texture: u32) -> void public ffi fn glClientActiveTextureARB(texture: u32) -> void public ffi fn glMultiTexCoord1dARB(target: u32, s: f64) -> void public ffi fn glMultiTexCoord1dvARB(target: u32, v: &f64) -> void public ffi fn glMultiTexCoord1fARB(target: u32, s: f32) -> void public ffi fn glMultiTexCoord1fvARB(target: u32, v: &f32) -> void public ffi fn glMultiTexCoord1iARB(target: u32, s: i32) -> void public ffi fn glMultiTexCoord1ivARB(target: u32, v: &i32) -> void public ffi fn glMultiTexCoord1sARB(target: u32, s: i16) -> void public ffi fn glMultiTexCoord1svARB(target: u32, v: &i16) -> void public ffi fn glMultiTexCoord2dARB(target: u32, s: f64, t: f64) -> void public ffi fn glMultiTexCoord2dvARB(target: u32, v: &f64) -> void public ffi fn glMultiTexCoord2fARB(target: u32, s: f32, t: f32) -> void public ffi fn glMultiTexCoord2fvARB(target: u32, v: &f32) -> void public ffi fn glMultiTexCoord2iARB(target: u32, s: i32, t: i32) -> void public ffi fn glMultiTexCoord2ivARB(target: u32, v: &i32) -> void public ffi fn glMultiTexCoord2sARB(target: u32, s: i16, t: i16) -> void public ffi fn glMultiTexCoord2svARB(target: u32, v: &i16) -> void public ffi fn glMultiTexCoord3dARB(target: u32, s: f64, t: f64, r: f64) -> void public ffi fn glMultiTexCoord3dvARB(target: u32, v: &f64) -> void public ffi fn glMultiTexCoord3fARB(target: u32, s: f32, t: f32, r: f32) -> void public ffi fn glMultiTexCoord3fvARB(target: u32, v: &f32) -> void public ffi fn glMultiTexCoord3iARB(target: u32, s: i32, t: i32, r: i32) -> void public ffi fn glMultiTexCoord3ivARB(target: u32, v: &i32) -> void public ffi fn glMultiTexCoord3sARB(target: u32, s: i16, t: i16, r: i16) -> void public ffi fn glMultiTexCoord3svARB(target: u32, v: &i16) -> void public ffi fn glMultiTexCoord4dARB(target: u32, s: f64, t: f64, r: f64, q: f64) -> void public ffi fn glMultiTexCoord4dvARB(target: u32, v: &f64) -> void public ffi fn glMultiTexCoord4fARB(target: u32, s: f32, t: f32, r: f32, q: f32) -> void public ffi fn glMultiTexCoord4fvARB(target: u32, v: &f32) -> void public ffi fn glMultiTexCoord4iARB(target: u32, s: i32, t: i32, r: i32, q: i32) -> void public ffi fn glMultiTexCoord4ivARB(target: u32, v: &i32) -> void public ffi fn glMultiTexCoord4sARB(target: u32, s: i16, t: i16, r: i16, q: i16) -> void public ffi fn glMultiTexCoord4svARB(target: u32, v: &i16) -> void ================================================ FILE: libs/OpenGL/GLUT.flx ================================================ // GLUT.flx // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. public namespace GLUT { public let RGB: i32 = 0 public let RGBA: i32 = 0 public let INDEX: i32 = 1 public let SINGLE: i32 = 0 public let DOUBLE: i32 = 2 public let ACCUM: i32 = 4 public let ALPHA: i32 = 8 public let DEPTH: i32 = 16 public let STENCIL: i32 = 32 } public ffi fn glutInit(argcp: &i32, argv: &&i8) public ffi fn glutInitDisplayMode(mode: u32) public ffi fn glutInitDisplayString(s: &i8) public ffi fn glutInitWindowPosition(x: i32, y: i32) public ffi fn glutInitWindowSize(width: i32, height: i32) public ffi fn glutMainLoop() public ffi fn glutCreateWindow(title: &i8) -> i32 public ffi fn glutCreateSubWindow(win: i32, x: i32, y: i32, width: i32, height: i32) -> i32 public ffi fn glutDestroyWindow(win: i32) -> void public ffi fn glutPostRedisplay() -> void public ffi fn glutPostWindowRedisplay(win: i32) -> void public ffi fn glutSwapBuffers() -> void public ffi fn glutGetWindow() -> i32 public ffi fn glutSetWindow(win: i32) -> void public ffi fn glutSetWindowTitle(title: &i8) -> void public ffi fn glutSetIconTitle(title: &i8) -> void public ffi fn glutPositionWindow(x: i32, y: i32) -> void public ffi fn glutReshapeWindow(width: i32, height: i32) -> void public ffi fn glutPopWindow() -> void public ffi fn glutPushWindow() -> void public ffi fn glutIconifyWindow() -> void public ffi fn glutShowWindow() -> void public ffi fn glutHideWindow() -> void public ffi fn glutFullScreen() -> void public ffi fn glutSetCursor(cursor: i32) -> void public ffi fn glutWarpPointer(x: i32, y: i32) -> void public ffi fn glutSolidDodecahedron() -> void ================================================ FILE: libs/SDL2/Keyboard.flx ================================================ // Keyboard.flx // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. export SDL::Keyboard public enum Key: u32 { case UNKNOWN = 0 case Backspace = 0x08 case Tab = 0x09 case Return = 0x0D case Escape = 0x1B case Space = 0x20 case Exclaim = 0x21 case DoubleQuote = 0x21 case Hash = 0x22 case Dollar = 0x23 case Percent = 0x24 case Ampersand = 0x25 case Quote = 0x26 case LeftParen = 0x27 case RightParen = 0x28 case Asterisk = 0x29 case Plus = 0x2A case Comma = 0x2B case Minus = 0x2C case Period = 0x2D case Slash = 0x2E case Zero = 0x2F case One = 0x30 case Two = 0x31 case Three = 0x32 case Four = 0x33 case Five = 0x34 case Six = 0x35 case Seven = 0x36 case Eight = 0x37 case Nine = 0x38 case Ten = 0x39 case Colon = 0x3A case Semicolon = 0x3B case Less = 0x3C case Equals = 0x3D case Greater = 0x3E case Question = 0x3F case At = 0x40 // Skip uppercase letters case LeftBracket = 0x41 case Backslash = 0x42 case RightBracket = 0x45 case Caret = 0x46 case Underscore = 0x47 case Backquote = 0x48 case A = 0x61 case B = 0x62 case C = 0x63 case D = 0x64 case E = 0x65 case F = 0x66 case G = 0x67 case H = 0x68 case I = 0x69 case J = 0x6A case K = 0x6B case L = 0x6C case M = 0x6D case N = 0x6E case O = 0x6F case P = 0x70 case Q = 0x71 case R = 0x72 case S = 0x73 case T = 0x74 case U = 0x75 case V = 0x76 case W = 0x77 case X = 0x78 case Y = 0x79 case Z = 0x7A /*CAPSLOCK = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CAPSLOCK), F1 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F1), F2 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F2), F3 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F3), F4 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F4), F5 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F5), F6 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F6), F7 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F7), F8 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F8), F9 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F9), F10 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F10), F11 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F11), F12 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F12), PRINTSCREEN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PRINTSCREEN), SCROLLLOCK = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SCROLLLOCK), PAUSE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PAUSE), INSERT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_INSERT), HOME = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_HOME), PAGEUP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PAGEUP), DELETE = '\177', END = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_END), PAGEDOWN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PAGEDOWN), RIGHT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RIGHT), LEFT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LEFT), DOWN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_DOWN), UP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_UP), NUMLOCKCLEAR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_NUMLOCKCLEAR), KP_DIVIDE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_DIVIDE), KP_MULTIPLY = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MULTIPLY), KP_MINUS = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MINUS), KP_PLUS = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_PLUS), KP_ENTER = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_ENTER), KP_1 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_1), KP_2 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_2), KP_3 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_3), KP_4 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_4), KP_5 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_5), KP_6 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_6), KP_7 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_7), KP_8 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_8), KP_9 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_9), KP_0 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_0), KP_PERIOD = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_PERIOD), APPLICATION = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_APPLICATION), POWER = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_POWER), KP_EQUALS = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_EQUALS), F13 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F13), F14 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F14), F15 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F15), F16 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F16), F17 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F17), F18 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F18), F19 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F19), F20 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F20), F21 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F21), F22 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F22), F23 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F23), F24 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F24), EXECUTE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_EXECUTE), HELP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_HELP), MENU = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MENU), SELECT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SELECT), STOP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_STOP), AGAIN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AGAIN), UNDO = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_UNDO), CUT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CUT), COPY = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_COPY), PASTE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PASTE), FIND = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_FIND), MUTE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MUTE), VOLUMEUP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_VOLUMEUP), VOLUMEDOWN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_VOLUMEDOWN), KP_COMMA = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_COMMA), KP_EQUALSAS400 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_EQUALSAS400), ALTERASE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_ALTERASE), SYSREQ = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SYSREQ), CANCEL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CANCEL), CLEAR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CLEAR), PRIOR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PRIOR), RETURN2 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RETURN2), SEPARATOR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SEPARATOR), OUT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_OUT), OPER = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_OPER), CLEARAGAIN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CLEARAGAIN), CRSEL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CRSEL), EXSEL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_EXSEL), KP_00 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_00), KP_000 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_000), THOUSANDSSEPARATOR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_THOUSANDSSEPARATOR), DECIMALSEPARATOR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_DECIMALSEPARATOR), CURRENCYUNIT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CURRENCYUNIT), CURRENCYSUBUNIT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CURRENCYSUBUNIT), KP_LEFTPAREN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_LEFTPAREN), KP_RIGHTPAREN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_RIGHTPAREN), KP_LEFTBRACE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_LEFTBRACE), KP_RIGHTBRACE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_RIGHTBRACE), KP_TAB = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_TAB), KP_BACKSPACE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_BACKSPACE), KP_A = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_A), KP_B = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_B), KP_C = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_C), KP_D = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_D), KP_E = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_E), KP_F = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_F), KP_XOR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_XOR), KP_POWER = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_POWER), KP_PERCENT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_PERCENT), KP_LESS = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_LESS), KP_GREATER = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_GREATER), KP_AMPERSAND = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_AMPERSAND), KP_DBLAMPERSAND = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_DBLAMPERSAND), KP_VERTICALBAR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_VERTICALBAR), KP_DBLVERTICALBAR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_DBLVERTICALBAR), KP_COLON = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_COLON), KP_HASH = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_HASH), KP_SPACE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_SPACE), KP_AT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_AT), KP_EXCLAM = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_EXCLAM), KP_MEMSTORE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMSTORE), KP_MEMRECALL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMRECALL), KP_MEMCLEAR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMCLEAR), KP_MEMADD = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMADD), KP_MEMSUBTRACT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMSUBTRACT), KP_MEMMULTIPLY = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMMULTIPLY), KP_MEMDIVIDE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMDIVIDE), KP_PLUSMINUS = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_PLUSMINUS), KP_CLEAR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_CLEAR), KP_CLEARENTRY = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_CLEARENTRY), KP_BINARY = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_BINARY), KP_OCTAL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_OCTAL), KP_DECIMAL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_DECIMAL), KP_HEXADECIMAL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_HEXADECIMAL), LCTRL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LCTRL), LSHIFT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LSHIFT), LALT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LALT), LGUI = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LGUI), RCTRL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RCTRL), RSHIFT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RSHIFT), RALT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RALT), RGUI = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RGUI), MODE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MODE), AUDIONEXT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AUDIONEXT), AUDIOPREV = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AUDIOPREV), AUDIOSTOP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AUDIOSTOP), AUDIOPLAY = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AUDIOPLAY), AUDIOMUTE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AUDIOMUTE), MEDIASELECT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MEDIASELECT), WWW = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_WWW), MAIL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MAIL), CALCULATOR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CALCULATOR), COMPUTER = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_COMPUTER), AC_SEARCH = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_SEARCH), AC_HOME = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_HOME), AC_BACK = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_BACK), AC_FORWARD = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_FORWARD), AC_STOP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_STOP), AC_REFRESH = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_REFRESH), AC_BOOKMARKS = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_BOOKMARKS), BRIGHTNESSDOWN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_BRIGHTNESSDOWN), BRIGHTNESSUP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_BRIGHTNESSUP), DISPLAYSWITCH = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_DISPLAYSWITCH), KBDILLUMTOGGLE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KBDILLUMTOGGLE), KBDILLUMDOWN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KBDILLUMDOWN), KBDILLUMUP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KBDILLUMUP), EJECT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_EJECT), SLEEP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SLEEP)*/ } // #define SCANCODE_MASK (1<<30) // #define SDL_SCANCODE_TO_KEYCODE(X) (X | SCANCODE_MASK) // enum // { // }; // /** // * \brief Enumeration of valid key mods (possibly OR'd together). // */ // typedef enum // { // KMOD_NONE = 0x0000, // KMOD_LSHIFT = 0x0001, // KMOD_RSHIFT = 0x0002, // KMOD_LCTRL = 0x0040, // KMOD_RCTRL = 0x0080, // KMOD_LALT = 0x0100, // KMOD_RALT = 0x0200, // KMOD_LGUI = 0x0400, // KMOD_RGUI = 0x0800, // KMOD_NUM = 0x1000, // KMOD_CAPS = 0x2000, // KMOD_MODE = 0x4000, // KMOD_RESERVED = 0x8000 // } SDL_Keymod; // #define KMOD_CTRL (KMOD_LCTRL|KMOD_RCTRL) // #define KMOD_SHIFT (KMOD_LSHIFT|KMOD_RSHIFT) // #define KMOD_ALT (KMOD_LALT|KMOD_RALT) // #define KMOD_GUI (KMOD_LGUI|KMOD_RGUI) ================================================ FILE: libs/SDL2/SDL.flx ================================================ // SDL.flx // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. export SDL import "Keyboard.flx" public let INIT_TIMER: u32 = 0x00000001 public let INIT_AUDIO: u32 = 0x00000010 public let INIT_VIDEO: u32 = 0x00000020 public let INIT_JOYSTICK: u32 = 0x00000200 public let INIT_HAPTIC: u32 = 0x00001000 public let INIT_GAMECONTROLLER: u32 = 0x00002000 public let INIT_EVENTS: u32 = 0x00004000 public let INIT_NOPARACHUTE: u32 = 0x00100000 public let INIT_EVERYTHING: u32 = INIT_TIMER | INIT_AUDIO | INIT_VIDEO | INIT_EVENTS | INIT_JOYSTICK | INIT_HAPTIC | INIT_GAMECONTROLLER public let GL_RED_SIZE: i32 = 0 public let GL_GREEN_SIZE: i32 = 1 public let GL_BLUE_SIZE: i32 = 2 public let GL_ALPHA_SIZE: i32 = 3 public let GL_BUFFER_SIZE: i32 = 4 public let GL_DOUBLEBUFFER: i32 = 5 public let GL_DEPTH_SIZE: i32 = 6 public let GL_STENCIL_SIZE: i32 = 7 public let GL_ACCUM_RED_SIZE: i32 = 8 public let GL_ACCUM_GREEN_SIZE: i32 = 9 public let GL_ACCUM_BLUE_SIZE: i32 = 10 public let GL_ACCUM_ALPHA_SIZE: i32 = 11 public let GL_STEREO: i32 = 12 public let GL_MULTISAMPLEBUFFERS: i32 = 13 public let GL_MULTISAMPLESAMPLES: i32 = 14 public let GL_ACCELERATED_VISUAL: i32 = 15 public let GL_RETAINED_BACKING: i32 = 16 public let GL_CONTEXT_MAJOR_VERSION: i32 = 17 public let GL_CONTEXT_MINOR_VERSION: i32 = 18 public let GL_CONTEXT_EGL: i32 = 19 public let GL_CONTEXT_FLAGS: i32 = 20 public let GL_CONTEXT_PROFILE_MASK: i32 = 21 public let GL_SHARE_WITH_CURRENT_CONTEXT: i32 = 22 public let GL_FRAMEBUFFER_SRGB_CAPABLE: i32 = 23 public let GL_CONTEXT_RELEASE_BEHAVIOR: i32 = 24 public enum EventType: u32 { case FIRSTEVENT = 0 case Quit = 0x100 case App_Terminating = 0x101 case App_LowMemory = 0x102 case App_WillEnterBackground = 0x103 case App_DidEnterBackground = 0x104 case App_WillEnterForeground = 0x105 case App_DidEnterForeground = 0x106 case WindowEvent = 0x200 case SysWMEvent = 0x201 case KeyDown = 0x300 case KeyUp = 0x301 case TextEditing = 0x302 case TextInput = 0x303 case KeymapChanged = 0x304 case Mouse_Motion = 0x400 case Mouse_ButtonDown = 0x401 case Mouse_ButtonUp = 0x402 case Mouse_Wheel = 0x403 case Joy_AxisMotion = 0x600 case Joy_BallMotion = 0x601 case Joy_HatMotion = 0x602 case Joy_ButtonDown = 0x603 case Joy_ButtonUp = 0x604 case Joy_DeviceAdded = 0x605 case Joy_DeviceRemoved = 0x606 case Controller_AxisMotion = 0x650 case Controller_ButtonDown = 0x651 case Controller_ButtonUp = 0x652 case Controller_DeviceAdded = 0x653 case Controller_DeviceRemoved = 0x654 case Controller_DeviceRemapped = 0x655 case FingerDown = 0x700 case FingerUp = 0x701 case FingerMotion = 0x702 case DollarGesture = 0x800 case DollarRecord = 0x801 case MultiGesture = 0x802 case ClipboardUpdate = 0x900 case DropFile = 0x1000 case Audio_DeviceAdded = 0x1100 case Audio_DeviceRemoved = 0x1101 case Render_TargetsReset = 0x2000 case Render_DeviceReset = 0x2001 case USEREVENT = 0x8000 case LASTEVENT = 0xFFFF } public struct Event { type: EventType lol: [i8: 52] } struct KeySym { // SDL_Scancode scancode scancode: u32 sym: Keyboard::Key mod: u16 unused: u32 } public struct KeyboardEvent { type: EventType timestamp: u32 windowid: u32 state: u8 repeat: u8 padding: u16 keysym: KeySym } public ffi fn SDL_Init(flags: u32) -> i32 public ffi fn SDL_CreateWindow(title: &i8, xpos: i32, ypos: i32, width: i32, height: i32, flags: u32) -> &void public ffi fn SDL_GL_SetAttribute(attr: i32, value: i32) public ffi fn SDL_PollEvent(event: &SDL::Event) -> i32 // opengl stuff public ffi fn SDL_GL_CreateContext(window: &void) -> &void public ffi fn SDL_GL_SwapWindow(window: &void) -> void ================================================ FILE: libs/libc.flx ================================================ // libc.flx // Copyright (c) 2014 - 2015, zhiayang // Licensed under the Apache License Version 2.0. export libc // printing public ffi fn puts(fmt: &i8) -> i32 public ffi fn printf(fmt: &i8, ...) -> i32 public ffi fn sprintf(fmt: &i8, y: &i8, ...) -> i32 public ffi fn snprintf(fmt: &i8, l: u64, y: &i8, ...) -> i32 public ffi fn fprintf(stream: &void, y: &i8, ...) -> i32 public ffi fn putchar(x: i32) -> i32 // memcpy/set/move public ffi fn memcpy(dest: &i8, source: &i8, length: u64) -> &i8 public ffi fn memmove(dest: &i8, source: &i8, length: u64) -> &i8 public ffi fn memset(dest: &i8, value: i32, length: u64) -> &i8 // heap // public ffi fn malloc(size: i64) -> &i8 // public ffi fn free(pointer: &i8) // strings public ffi fn strlen(s: &i8) -> i64 public ffi fn strcmp(s1: &i8, s2: &i8) -> i32 public ffi fn strncmp(s1: &i8, s2: &i8, length: i64) -> i32 // random things public ffi fn usleep(usec: u32) -> i32 public ffi fn sleep(sec: u32) -> u32 public ffi fn abort() public ffi fn exit(status: i32) // file stuff public ffi fn fsync(fd: i32) -> i32 public ffi fn fflush(fd: &void) -> i32 public ffi fn ioctl(fd: i32, cmd: u64, ...) -> i32 public ffi fn fopen(path: &i8, mode: &i8) -> &void public ffi fn fread(buf: &i8, sz: u64, cnt: u64, file: &void) -> u64 public ffi fn fclose(file: &void) -> i32 // unistd.h // posix stuff, that windows likes to rename for some reason!!!!! #if os::name == "windows" { // unistd.h public ffi fn open(path: &i8, flags: i32, mode: i32) -> i32 as "_open" public ffi fn close(fd: i32) -> i32 as "_close" public ffi fn read(fd: i32, buf: &i8, count: i64) -> i64 as "_read" public ffi fn write(fd: i32, buf: &i8, count: i64) -> i64 as "_write" public ffi fn lseek(fd: i32, ofs: i64, whence: i32) -> i64 as "_lseek" // stdio.h public ffi fn fdopen(fd: i32, mode: &i8) -> &void as "_fdopen" } else { // unistd.h public ffi fn open(path: &i8, flags: i32, mode: i32) -> i32 public ffi fn close(fd: i32) -> i32 public ffi fn read(fd: i32, buf: &i8, count: i64) -> i64 public ffi fn write(fd: i32, buf: &i8, count: i64) -> i64 public ffi fn lseek(fd: i32, ofs: i64, whence: i32) -> i64 // stdio.h public ffi fn fdopen(fd: i32, mode: &i8) -> &void } ================================================ FILE: libs/os.flx ================================================ // os.flx // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. export os ================================================ FILE: libs/std/file.flx ================================================ // file.flx // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. export std::io import libc // // rudimentary file handling // public struct File // { // fd: int // buf: [i8] // } // public enum Mode // { // case Read // case Write // case ReadWrite // case Append // } // let O_RDONLY: i32 = 0x0000 // open for reading only // let O_WRONLY: i32 = 0x0001 // open for writing only // let O_RDWR: i32 = 0x0002 // open for reading and writing // let O_ACCMODE: i32 = 0x0003 // mask for above modes // let O_NONBLOCK: i32 = 0x0004 // no delay // let O_APPEND: i32 = 0x0008 // set append mode // let O_CREAT: i32 = 0x0200 // create if nonexistant // let O_TRUNC: i32 = 0x0400 // truncate to zero length // let O_EXCL: i32 = 0x0800 // error if already exists // let SEEK_SET: i32 = 0 // set file offset to offset // let SEEK_CUR: i32 = 1 // set file offset to current plus offset // let SEEK_END: i32 = 2 // set file offset to EOF plus offset // public fn open(path: str, mode: Mode) -> File // { // var flags: i32 // if mode == Mode::Read => flags = O_RDONLY // if mode == Mode::Write => flags = O_WRONLY // if mode == Mode::ReadWrite => flags = O_RDWR // if mode == Mode::Append => flags = O_RDWR | O_APPEND // return File(fd: libc::open(path, flags, 0), buf: [ ]) // } // public fn read(f: File) -> [i8] // { // if f.buf.length != 0 => return f.buf // return [ ] // } ================================================ FILE: libs/std/io.flx ================================================ // io.flx // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. export std::io public import file as _ public import print as _ ================================================ FILE: libs/std/limits.flx ================================================ // limits.flx // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. export std::limits public namespace int8 { public let min: i8 = -128 public let max: i8 = +127 } public namespace int16 { public let min: i16 = -32768 public let max: i16 = +32767 } public namespace int32 { public let min: i32 = -2147483648 public let max: i32 = +2147483647 } public namespace int64 { public let min: i64 = -9223372036854775808 public let max: i64 = +9223372036854775807 } public namespace uint8 { public let min: u8 = 0 public let max: u8 = 255 } public namespace uint16 { public let min: u16 = 0 public let max: u16 = 65535 } public namespace uint32 { public let min: u32 = 0 public let max: u32 = 4294967295 } public namespace uint64 { public let min: u64 = 0 public let max: u64 = 18446744073709551615 } ================================================ FILE: libs/std/map.flx ================================================ // map.flx // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. export std import libc import std::opt // haphazardly taken from http://sidsen.azurewebsites.net/papers/rb-trees-talg.pdf public class map { struct node { var parent: &node var left: &node var right: &node var key: K var value: V var rank: int } var root: &node var size: int init() { root = null size = 0 } fn _rotateLeft(n: &node) { var r = n.right n.right = r.left if(r.left != null) => r.left.parent = n r.parent = n.parent if(n.parent == null) => root = r else if(n.parent.left == n) => n.parent.left = r else => n.parent.right = r r.left = n n.parent = r } fn _rotateRight(n: &node) { var l = n.left n.left = l.right if(l.right != null) => l.right.parent = n l.parent = n.parent if(n.parent == null) => root = l else if(n.parent.right == n) => n.parent.right = l else => n.parent.left = l l.right = n n.parent = l } fn _getPredecessor(node: &node) -> &node { if(node == null) => return null else if(node.left != null) { var l = node.left while(l.right != null) => l = l.right return l } else { // keep searching upwards till we find something on our left. var par = node.parent var chd = node while(par != null && chd == par.left) { chd = par par = par.parent } return par } } fn _getSuccessor(node: &node) -> &node { if(node == null) => return null else if(node.right != null) { var r = node.right while(r.left != null) => r = r.left return r } else { var par = node.parent var chd = node while(par != null && chd == par.right) { chd = par par = par.parent } return par } } // returns true if we inserted a new value, false if the key already existed fn insert(key: K, val: V) -> bool { if(root == null) { root = alloc node(key: key, value: val, rank: 0) size = 1 return true } else { return _insert(key, val, root) } } fn _insert(key: K, val: V, _n: &node) -> bool { fn checkLeftUnbal(n: &node) -> bool { if(n.left == null) { if(n.rank == 1) => return true else => return false } else if(n.rank >= n.left.rank + 2) { return true } else { return false } } fn checkRightUnbal(n: &node) -> bool { if(n.right == null) { if(n.rank == 1) => return true else => return false } else if(n.rank >= n.right.rank + 2) { return true } else { return false } } // args are immutable. var n = _n var side = 0 // -1 for left, 1 for right if(n.key == key) => return false else if(key < n.key) { side = -1 if(n.left == null) { n.left = alloc node(key: key, value: val, parent: n) if(n.left == null) { libc::printf("node alloc failed!\n") libc::abort() } } else => return _insert(key, val, n.left) } else { side = 1 if(n.right == null) { n.right = alloc node(key: key, value: val, parent: n) if(n.right == null) { libc::printf("node alloc failed!\n") libc::abort() } } else => return _insert(key, val, n.right) } if(n.parent != null && n.parent.rank == 0) { n.parent.rank += 1 var par = n.parent while(par != null && n.rank + 1 != par.rank) { if(side == -1) { if(checkRightUnbal(par)) { if(n.left == null || n.rank >= n.left.rank + 2) { n.rank -= 1 n.right.rank += 1 _rotateLeft(n) } par.rank -= 1 _rotateRight(par) break } } else { if(checkLeftUnbal(par)) { if(n.right == null || n.rank >= n.right.rank + 2) { n.rank -= 1 n.left.rank += 1 _rotateRight(n) } par.rank -= 1 _rotateLeft(par) break } } n = par par = n.parent n.rank += 1 } } size += 1 return true } fn _rebalance(_n: &node, _p: &node, _s: &node) { fn nodeIs22(n: &node) -> bool { if(n == null || n.rank == 0) => return false if(n.rank == 1) => return (n.left == null && n.right == null) else => return (n.left.rank == n.right.rank && n.left.rank + 2 == n.rank) } fn _rank(n: &node) -> int { if(n == null) => return -1 else => return n.rank } var n = _n var parent = _p var sibling = _s var deltaRank = parent.rank - n.rank while(deltaRank == 3 || parent.rank == 1 && nodeIs22(parent)) { var deltaRankSibling = 0 if(sibling == null) => deltaRankSibling = parent.rank + 1 else => deltaRankSibling = parent.rank - sibling.rank if(deltaRankSibling == 2) { parent.rank -= 1 } else { let drsL = sibling.rank - _rank(sibling.left) let drsR = sibling.rank - _rank(sibling.right) if(drsL == 2 && drsR == 2) { parent.rank -= 1 sibling.rank -= 1 } else if(parent.right == sibling) { if(drsR == 1) { sibling.rank += 1 parent.rank -= 1 if(sibling.left == null) => parent.rank -= 1 _rotateLeft(parent) } else { parent.rank -= 2 sibling.rank -= 1 sibling.left.rank += 2 _rotateRight(sibling) _rotateLeft(parent) } break } else { if(drsL == 1) { sibling.rank += 1 parent.rank -= 1 if(sibling.right == null) => parent.rank -= 1 _rotateRight(parent) } else { parent.rank -= 2 sibling.rank -= 1 sibling.right.rank += 2 _rotateLeft(sibling) _rotateRight(parent) } break } } if(parent.parent == null) => return n = parent parent = parent.parent if(parent.left == n) => sibling = parent.right else => sibling = parent.left deltaRank = parent.rank - n.rank } } // returns true if the key was found, false if not. fn remove(key: K) -> bool { var n = _search(key, root) if(n == null) => return false // ok, now remove the node from the thing. size -= 1 if(n.left == null && n.right == null && n == root) { // if we're the only node then just delete us and go away free n root = null return true } if(n.left != null && n.right != null) { let p = _getPredecessor(n) n.key = p.key n.value = p.value n = p } var replacement: &node = null if(n.left != null) => replacement = n.left else => replacement = n.right if(replacement != null) { var sibling: &node = null replacement.parent = n.parent if(n.parent == null) { root = replacement return true } else if(n == n.parent.left) { n.parent.left = replacement sibling = n.parent.right } else { n.parent.right = replacement sibling = n.parent.left } n.left = null n.right = null n.parent = null _rebalance(replacement, replacement.parent, sibling) } else { let rebalNode = n.parent var sibling: &node = null if(n == n.parent.left) { n.parent.left = null sibling = rebalNode.right } else if(n == n.parent.right) { n.parent.right = null sibling = rebalNode.left } n.parent = null n.rank -= 1 _rebalance(n, rebalNode, sibling) } return true } fn search(key: K) -> std::opt! { let n = _search(key, root) if(n == null) => return std::opt!::none else => return std::opt::some(n.value) } fn _search(key: K, n: &node) -> &node { if(n == null) => return null if(n.key == key) => return n if(key < n.key) => return _search(key, n.left) else => return _search(key, n.right) } } ================================================ FILE: libs/std/math.flx ================================================ // math.flx // Copyright (c) 2014 - 2015, zhiayang // Licensed under the Apache License Version 2.0. export math public ffi fn sqrt(x: f64) -> f64 public ffi fn sqrtf(x: f32) -> f32 public ffi fn log(x: f64) -> f64 public ffi fn logf(x: f32) -> f32 public ffi fn floor(x: f64) -> f64 public ffi fn floorf(x: f32) -> f32 public ffi fn pow(x: f64, y: f64) -> f64 public ffi fn powf(x: f32, y: f32) -> f32 public let π: f64 = 3.14159265358979323846264338327950 public let pi: f64 = 3.14159265358979323846264338327950 ================================================ FILE: libs/std/opt.flx ================================================ // opt.flx // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. export std public union opt { some: T none } ================================================ FILE: libs/std/print.flx ================================================ // print.flx // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. export std::io import libc fn error(msg: str) { libc::printf("invalid format string: '%s'\n", msg) libc::abort() } fn to_string_i64(n: i64) -> string { var ret = @raw alloc i8 [16] let len = libc::sprintf(ret, "%lld", n) let s = string(ret, len) free ret return s } fn to_string_u64(n: u64) -> string { var ret = @raw alloc i8 [16] let len = libc::sprintf(ret, "%llu", n) let s = string(ret, len) free ret return s } fn to_string_f64(n: f64) -> string { var ret = @raw alloc i8 [24] let len = libc::sprintf(ret, "%f", n) let s = string(ret, len) free ret return s } public fn format(fmt: str, args: [any: ...]) -> string { // todo: this is quite inefficient. // should we make some kind of stringbuilder class? var ret: string var argi = 0 var idx = 0 while idx < fmt.length { let ch = fmt[idx] if ch == '%' { if argi >= args.length { error(format("too few arguments: got only %, expected at least %", args.length, argi + 1)) } else { let arg = args[argi] argi += 1 if arg is u8 => ret.append(to_string_u64(arg as u8)) else if arg is u16 => ret.append(to_string_u64(arg as u16)) else if arg is u32 => ret.append(to_string_u64(arg as u32)) else if arg is u64 => ret.append(to_string_u64(arg as u64)) else if arg is i8 => ret.append(to_string_i64(arg as i8)) else if arg is i16 => ret.append(to_string_i64(arg as i16)) else if arg is i32 => ret.append(to_string_i64(arg as i32)) else if arg is i64 => ret.append(to_string_i64(arg as i64)) else if arg is f32 => ret.append(to_string_f64(arg as f32)) else if arg is f64 => ret.append(to_string_f64(arg as f64)) else if arg is string => ret.append(arg as string) else if arg is str => ret.append(arg as str) else => ret.append("(?)") } } else { if ch == '\\' { idx += 1 ret.append(fmt[idx]) } else { ret.append(ch) } } idx += 1 } return ret } // in case you're lazy public fn println() { libc::puts("") } public fn println(fmt: str, args: [any: ...]) { libc::puts(format(fmt, ...args)) } public fn print(fmt: str, args: [any: ...]) { let s = format(fmt, ...args) libc::write(1, s.ptr, s.length) } ================================================ FILE: libs/std/set.flx ================================================ // set.flx // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. export std public class set { struct node { var parent: &node var left: &node var right: &node var data: T } var root: &node } ================================================ FILE: meson.build ================================================ # meson.build project('flax', version: '0.41.7-pre', default_options: [ 'warning_level=3' ]) add_languages(['c', 'cpp']) the_compiler = meson.get_compiler('c') if the_compiler.get_id() == 'msvc' add_project_arguments('/utf-8', language: ['c', 'cpp']) add_project_arguments('/std:c++latest', language: 'cpp') add_project_arguments('/permissive-', language: 'cpp') add_project_arguments('-D_STDC_LIMIT_MACROS', language: 'cpp') add_project_arguments('-D_SCL_SECURE_NO_WARNINGS', language: ['c', 'cpp']) add_project_arguments('-D_CRT_SECURE_NO_WARNINGS', language: ['c', 'cpp']) add_project_arguments('-D_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING', language: 'cpp') add_project_arguments('/W4', language: ['c', 'cpp']) # disable some useless warnings: add_project_arguments('/wd4100', language: ['c', 'cpp']) # unused function parameter add_project_arguments('/wd4127', language: ['c', 'cpp']) # if expression is constant (msvc apparently doesn't understand &&) add_project_arguments('/wd4456', language: ['c', 'cpp']) # local variable shadowing add_project_arguments('/wd4457', language: ['c', 'cpp']) # function parameter shadowing add_project_arguments('/wd4458', language: ['c', 'cpp']) # class member shadowing # enable some useful warnings (set them to fire at level 1): add_project_arguments('/w14062', language: ['c', 'cpp']) # enum value not handled in switch-case add_project_arguments('/w14263', language: ['c', 'cpp']) # member method hides base method add_project_arguments('/w14265', language: ['c', 'cpp']) # non-virtual destructor when class has virtual methods add_project_arguments('/w14548', language: ['c', 'cpp']) # first part of comma-expression has no side-effects # until meson fixes the PCH issue on MSVC (https://github.com/mesonbuild/meson/issues/5648) # we must force include precompile.h to get the STL types! add_project_arguments('/FIsource/include/precompile.h', language: 'cpp') add_project_link_arguments('/ignore:4099', language: ['c', 'cpp']) add_project_link_arguments('/machine:X64', language: ['c', 'cpp']) add_project_link_arguments('/opt:noref', language: ['c', 'cpp']) # add_project_link_arguments('/incremental', language: ['c', 'cpp']) add_project_link_arguments('/nodefaultlib:libcmt.lib', language: ['c', 'cpp']) add_project_link_arguments('/nodefaultlib:libcmtd.lib', language: ['c', 'cpp']) if get_option('buildtype') == 'debug' libKind = 'Debug' else libKind = 'Release' endif # ok, so because meson is dumb, and we want to allow configuring the locations *without* editing this file # eg. in CI environments, we run an external command that's just an echo of the environment variable, and # capture the output to use. all because it's apparently "a bad idea" to allow people to read env vars... envname_mpir = '%MPIR_ROOT_DIR%' envname_mpfr = '%MPFR_ROOT_DIR%' envname_llvm = '%LLVM_ROOT_DIR%' envname_libffi = '%LIBFFI_ROOT_DIR%' llvm_version = '11.0.0' mpir_root_dir = run_command('cmd.exe', '/C', 'echo', envname_mpir).stdout().strip() if mpir_root_dir == envname_mpir mpir_root_dir = 'D:/Projects/lib/mpir' endif mpfr_root_dir = run_command('cmd.exe', '/C', 'echo', envname_mpfr).stdout().strip() if mpfr_root_dir == envname_mpfr mpfr_root_dir = 'D:/Projects/lib/mpfr' endif llvm_root_dir = run_command('cmd.exe', '/C', 'echo', envname_llvm).stdout().strip() if llvm_root_dir == envname_llvm llvm_root_dir = 'D:/Projects/lib/llvm/' + llvm_version endif libffi_root_dir = run_command('cmd.exe', '/C', 'echo', envname_libffi).stdout().strip() if libffi_root_dir == envname_libffi libffi_root_dir = 'D:/Projects/lib/libffi' endif message('mpir_root: ' + mpir_root_dir) message('mpfr_root: ' + mpfr_root_dir) message('llvm_root: ' + llvm_root_dir) message('libffi_root: ' + libffi_root_dir) mpir_hdr_dir = mpir_root_dir + '/' + libKind + '/include/' mpfr_hdr_dir = mpfr_root_dir + '/' + libKind + '/include/' llvm_hdr_dir = llvm_root_dir + '/' + libKind + '/include/' libffi_hdr_dir = libffi_root_dir + '/' + libKind + '/include/' mpir_lib_dir = mpir_root_dir + '/' + libKind + '/lib/' mpfr_lib_dir = mpfr_root_dir + '/' + libKind + '/lib/' llvm_lib_dir = llvm_root_dir + '/' + libKind + '/lib/' libffi_lib_dir = libffi_root_dir + '/' + libKind + '/lib/' legacy_stdio_dep = declare_dependency(dependencies: the_compiler.find_library('legacy_stdio_definitions')) mpir_dep = declare_dependency(version: '3.0.0', include_directories: include_directories(mpir_hdr_dir), dependencies: the_compiler.find_library('mpir', dirs: mpir_lib_dir)) mpfr_dep = declare_dependency(version: '4.0.0', include_directories: include_directories(mpfr_hdr_dir), dependencies: the_compiler.find_library('mpfr', dirs: mpfr_lib_dir)) libffi_dep = declare_dependency(version: '3.2.1', include_directories: include_directories(libffi_hdr_dir), dependencies: the_compiler.find_library('libffi', dirs: libffi_lib_dir)) llvm_dep = declare_dependency(version: llvm_version, include_directories: include_directories(llvm_hdr_dir), dependencies: [ mpfr_dep, mpir_dep, the_compiler.find_library('LLVMAnalysis', dirs: llvm_lib_dir), the_compiler.find_library('LLVMAsmPrinter', dirs: llvm_lib_dir), the_compiler.find_library('LLVMBinaryFormat', dirs: llvm_lib_dir), the_compiler.find_library('LLVMBitReader', dirs: llvm_lib_dir), the_compiler.find_library('LLVMBitstreamReader', dirs: llvm_lib_dir), the_compiler.find_library('LLVMBitWriter', dirs: llvm_lib_dir), the_compiler.find_library('LLVMCFGuard', dirs: llvm_lib_dir), the_compiler.find_library('LLVMCodegen', dirs: llvm_lib_dir), the_compiler.find_library('LLVMCore', dirs: llvm_lib_dir), the_compiler.find_library('LLVMDebugInfoCodeView', dirs: llvm_lib_dir), the_compiler.find_library('LLVMDebugInfoDWARF', dirs: llvm_lib_dir), the_compiler.find_library('LLVMDebugInfoGSYM', dirs: llvm_lib_dir), the_compiler.find_library('LLVMDebugInfoPDB', dirs: llvm_lib_dir), the_compiler.find_library('LLVMDebugInfoMSF', dirs: llvm_lib_dir), the_compiler.find_library('LLVMDemangle', dirs: llvm_lib_dir), the_compiler.find_library('LLVMExecutionEngine', dirs: llvm_lib_dir), the_compiler.find_library('LLVMGlobalISel', dirs: llvm_lib_dir), the_compiler.find_library('LLVMInstCombine', dirs: llvm_lib_dir), the_compiler.find_library('LLVMipo', dirs: llvm_lib_dir), the_compiler.find_library('LLVMJITLink', dirs: llvm_lib_dir), the_compiler.find_library('LLVMLibDriver', dirs: llvm_lib_dir), the_compiler.find_library('LLVMLinker', dirs: llvm_lib_dir), the_compiler.find_library('LLVMMC', dirs: llvm_lib_dir), the_compiler.find_library('LLVMMCDisassembler', dirs: llvm_lib_dir), the_compiler.find_library('LLVMMCJIT', dirs: llvm_lib_dir), the_compiler.find_library('LLVMMCParser', dirs: llvm_lib_dir), the_compiler.find_library('LLVMObject', dirs: llvm_lib_dir), the_compiler.find_library('LLVMOrcError', dirs: llvm_lib_dir), the_compiler.find_library('LLVMOrcJIT', dirs: llvm_lib_dir), the_compiler.find_library('LLVMPasses', dirs: llvm_lib_dir), the_compiler.find_library('LLVMProfileData', dirs: llvm_lib_dir), the_compiler.find_library('LLVMRemarks', dirs: llvm_lib_dir), the_compiler.find_library('LLVMRuntimeDyld', dirs: llvm_lib_dir), the_compiler.find_library('LLVMScalarOpts', dirs: llvm_lib_dir), the_compiler.find_library('LLVMSelectionDAG', dirs: llvm_lib_dir), the_compiler.find_library('LLVMSupport', dirs: llvm_lib_dir), the_compiler.find_library('LLVMTablegen', dirs: llvm_lib_dir), the_compiler.find_library('LLVMTarget', dirs: llvm_lib_dir), the_compiler.find_library('LLVMTextAPI', dirs: llvm_lib_dir), the_compiler.find_library('LLVMTransformUtils', dirs: llvm_lib_dir), the_compiler.find_library('LLVMVectorize', dirs: llvm_lib_dir), the_compiler.find_library('LLVMX86AsmParser', dirs: llvm_lib_dir), the_compiler.find_library('LLVMX86CodeGen', dirs: llvm_lib_dir), the_compiler.find_library('LLVMX86Desc', dirs: llvm_lib_dir), the_compiler.find_library('LLVMX86Info', dirs: llvm_lib_dir), ] ) all_deps = [ legacy_stdio_dep, mpir_dep, mpfr_dep, libffi_dep, llvm_dep ] else add_project_arguments('-std=c11', language: 'c') add_project_arguments('-std=c++17', language: 'cpp') # add_project_arguments('-include', 'source/include/precompile.h', language: 'cpp') add_project_arguments('-Wall', '-Wno-unused-parameter', '-Wno-sign-conversion', '-Wno-padded', '-Wno-conversion', '-Wno-shadow', '-Wno-missing-noreturn', '-Wno-unused-macros', '-Wno-switch-enum', '-Wno-deprecated', '-Wno-format-nonliteral', '-Wno-trigraphs', '-Wno-unused-const-variable', '-Wno-deprecated-declarations', '-Wno-unused-lambda-capture', '-Wno-unused-variable', language:'cpp') # on unix, we use GMP instead of MPIR. mpfr_dep = dependency('mpfr', version: '>= 4.0.0') libffi_dep = dependency('libffi', version: '>= 3.2.1') llvm_dep = dependency('llvm', static: true, version: '9.0.0', modules: [ 'core', 'engine', 'native', 'linker', 'bitwriter', 'lto', 'vectorize', 'all-targets', 'object', 'orcjit' ]) all_deps = [ mpfr_dep, libffi_dep, llvm_dep ] endif source_files = files([ 'source/main.cpp', 'source/misc/mpool.cpp', 'source/misc/allocator.cpp', 'source/misc/identifier.cpp', 'source/misc/destructors.cpp', 'source/repl/driver.cpp', 'source/repl/execute.cpp', 'source/repl/history.cpp', 'source/repl/commands.cpp', 'source/frontend/pts.cpp', 'source/frontend/file.cpp', 'source/frontend/lexer.cpp', 'source/frontend/errors.cpp', 'source/frontend/import.cpp', 'source/frontend/arguments.cpp', 'source/frontend/collector.cpp', 'source/frontend/dependencies.cpp', 'source/platform/compiler.cpp', 'source/platform/platform.cpp', 'source/platform/backtrace.cpp', 'source/platform/msvcfinder.cpp', 'source/frontend/parser/misc.cpp', 'source/frontend/parser/expr.cpp', 'source/frontend/parser/type.cpp', 'source/frontend/parser/literal.cpp', 'source/frontend/parser/variable.cpp', 'source/frontend/parser/function.cpp', 'source/frontend/parser/toplevel.cpp', 'source/frontend/parser/operators.cpp', 'source/frontend/parser/controlflow.cpp', 'source/backend/backend.cpp', 'source/backend/x64AsmBackend.cpp', 'source/backend/llvm/jit.cpp', 'source/backend/llvm/linker.cpp', 'source/backend/llvm/translator.cpp', 'source/backend/interp/driver.cpp', 'source/typecheck/misc.cpp', 'source/typecheck/call.cpp', 'source/typecheck/type.cpp', 'source/typecheck/using.cpp', 'source/typecheck/slice.cpp', 'source/typecheck/defer.cpp', 'source/typecheck/loops.cpp', 'source/typecheck/dotop.cpp', 'source/typecheck/enums.cpp', 'source/typecheck/alloc.cpp', 'source/typecheck/assign.cpp', 'source/typecheck/ranges.cpp', 'source/typecheck/sizeof.cpp', 'source/typecheck/unions.cpp', 'source/typecheck/traits.cpp', 'source/typecheck/special.cpp', 'source/typecheck/structs.cpp', 'source/typecheck/classes.cpp', 'source/typecheck/function.cpp', 'source/typecheck/variable.cpp', 'source/typecheck/literals.cpp', 'source/typecheck/toplevel.cpp', 'source/typecheck/subscript.cpp', 'source/typecheck/operators.cpp', 'source/typecheck/arithmetic.cpp', 'source/typecheck/directives.cpp', 'source/typecheck/destructure.cpp', 'source/typecheck/controlflow.cpp', 'source/typecheck/typecheckstate.cpp', 'source/typecheck/polymorph/misc.cpp', 'source/typecheck/polymorph/driver.cpp', 'source/typecheck/polymorph/solver.cpp', 'source/typecheck/polymorph/transforms.cpp', 'source/typecheck/polymorph/instantiator.cpp', 'source/typecheck/resolver/misc.cpp', 'source/typecheck/resolver/driver.cpp', 'source/typecheck/resolver/resolver.cpp', 'source/codegen/raii.cpp', 'source/codegen/misc.cpp', 'source/codegen/call.cpp', 'source/codegen/loops.cpp', 'source/codegen/slice.cpp', 'source/codegen/alloc.cpp', 'source/codegen/enums.cpp', 'source/codegen/dotop.cpp', 'source/codegen/ranges.cpp', 'source/codegen/sizeof.cpp', 'source/codegen/assign.cpp', 'source/codegen/unions.cpp', 'source/codegen/traits.cpp', 'source/codegen/structs.cpp', 'source/codegen/classes.cpp', 'source/codegen/logical.cpp', 'source/codegen/builtin.cpp', 'source/codegen/variable.cpp', 'source/codegen/function.cpp', 'source/codegen/toplevel.cpp', 'source/codegen/literals.cpp', 'source/codegen/operators.cpp', 'source/codegen/subscript.cpp', 'source/codegen/arithmetic.cpp', 'source/codegen/directives.cpp', 'source/codegen/destructure.cpp', 'source/codegen/refcounting.cpp', 'source/codegen/controlflow.cpp', 'source/codegen/constructor.cpp', 'source/codegen/autocasting.cpp', 'source/codegen/codegenstate.cpp', 'source/codegen/glue/any.cpp', 'source/codegen/glue/misc.cpp', 'source/codegen/glue/arrays.cpp', 'source/codegen/glue/strings.cpp', 'source/codegen/glue/saa_common.cpp', 'source/fir/interp/wrappers.cpp', 'source/fir/interp/compiler.cpp', 'source/fir/interp/interpreter.cpp', 'source/fir/ConstantValue.cpp', 'source/fir/GlobalValue.cpp', 'source/fir/Instruction.cpp', 'source/fir/IRBuilder.cpp', 'source/fir/Function.cpp', 'source/fir/IRBlock.cpp', 'source/fir/Module.cpp', 'source/fir/Value.cpp', 'source/fir/Name.cpp', 'source/fir/Types/DynamicArrayType.cpp', 'source/fir/Types/ArraySliceType.cpp', 'source/fir/Types/PrimitiveType.cpp', 'source/fir/Types/FunctionType.cpp', 'source/fir/Types/RawUnionType.cpp', 'source/fir/Types/PointerType.cpp', 'source/fir/Types/SingleTypes.cpp', 'source/fir/Types/OpaqueType.cpp', 'source/fir/Types/StructType.cpp', 'source/fir/Types/TypeUtils.cpp', 'source/fir/Types/ArrayType.cpp', 'source/fir/Types/TraitType.cpp', 'source/fir/Types/ClassType.cpp', 'source/fir/Types/TupleType.cpp', 'source/fir/Types/UnionType.cpp', 'source/fir/Types/EnumType.cpp', 'source/fir/Types/Type.cpp' ]) utf8rewind_dep = declare_dependency(include_directories: include_directories('external/utf8rewind/include'), sources: [ 'external/utf8rewind/source/utf8rewind.c', 'external/utf8rewind/source/unicodedatabase.c', 'external/utf8rewind/source/internal/seeking.c', 'external/utf8rewind/source/internal/database.c', 'external/utf8rewind/source/internal/streaming.c', 'external/utf8rewind/source/internal/codepoint.c', 'external/utf8rewind/source/internal/composition.c', 'external/utf8rewind/source/internal/casemapping.c', 'external/utf8rewind/source/internal/decomposition.c' ] ) tinyproclib_dep = declare_dependency(include_directories: include_directories('external/tinyprocesslib'), sources: [ 'external/tinyprocesslib/process.cpp', 'external/tinyprocesslib/process_os.cpp' ] ) executable('flaxc', source_files, include_directories: include_directories([ 'source/include', 'external' ]), dependencies: all_deps + [ tinyproclib_dep, utf8rewind_dep ], # cpp_pch: 'source/include/precompile.h' ) ================================================ FILE: notes.md ================================================ ## notes ## to fix 1. `public static` doesn't work, but `static public` works. 2. underlining breaks for multi-line spans; just don't underline in that case. 3. types don't appear before functions for some reason, for typechecking. (ie. order becomes important) 4. enum values are not working correctly (seems to be right-shifted by 8?) (the values are not assigned) 5. defer appears to be broken: ``` var i = 0 while true { defer i += 1 // doesn't change } ``` 6. "unsynchronised use of global init function!!!" -- need to figure out a way to serialise access to the global init function 7. polymorphic stuff breaks when manually instantiating 8. compiler crash: ``` import libc as _ struct Cat { fn greet() { printf("i love manga uwu\n") } } @entry fn main() { let c: Cat! = Cat() c.greet(); } ``` 9. ambiguous call to initialiser of class 10. assignment to runtime variable in #run block 11. numbers basically don't cast properly at all ## to refactor 3. all uses of defer() need to be audited. there are instances where an exception is thrown during typechecking as a result of unwrapping a `TCResult` that contains an error; as the stack unwinds, it may encounter a defer() object, which necessitates calling the code inside. - in general that is fine (most of the time, it's just `fs->pushLoc()` followed by `defer(fs->popLoc())`), but in some instances it is not fine --- most notably, when we push a body context and pop it in the defer. - since the popping of the body context asserts that the top of the stack is the same as what we expect, we might end up in a situation where exception-throwing function pushes a different context and throws before popping it, leaving the calling frame with an inconsistent view - the assertion will cause the compiler to terminate when it should have just printed the error message generated by the exception-throwing function. 4. instead of keeping a separate list of `unresolvedGenericDefns` which is pretty ugly, it should be feasible to create a sort of `sst::ParametricDefn` that simply contains a pointer to the original `ast::Parameterisable` as its only field; then, we should be able to simplify the typechecking code substantially by moving those the polymorph instantiation into that definition's typecheck method instead. 5. setting the method's containing class via the `infer` parameter feels super fucking dirty, and ngl it has felt dirty for the past 5 years. ## to investigate 1. we rely on a lot of places to set `enclosingScope` correctly when typechecking structs etc. there should be a better way to do this, probably automatically or something like that. basically anything except error-prone manual setting. ================================================ FILE: programs/fic/main.flx ================================================ // main.flx // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. // this is supposed to be an irc client, in case i forget. @entry fn main() { } ================================================ FILE: programs/fic/run.bat ================================================ @echo off robocopy libs build\sysroot\usr\local\lib\flaxlibs /e /nfl /ndl /njh /njs /nc /ns /np build\meson-rel\flaxc.exe -sysroot build\sysroot -run programs\fic\main.flx ================================================ FILE: roadmap.md ================================================ # Flax 1.0 Roadmap As more of the core features are slowly being finished up, the 1.0 milestone is in sight. This is just a list of things that should be finished before the initial implementation can be labelled "fit-for-use". Of course, this doesn't preclude any bugfixes that are necessary. ## Features 1. Traits 2. Extensions 3. Cleanup and modernise operator overloading 4. Standard library 5. Proper documentation for the entire language and all features 6. Proper introduction to language features (eg. for a README) ### Cleanup/modernise Operator Overloading The operator overloading mechanism is dated pre-resolver rewrite, which means that it probably isn't as extensible as we'd like it to be. For example, polymorphic operators aren't a possiblity currently, and that should be a thing that is allowed. ================================================ FILE: source/backend/backend.cpp ================================================ // Backend.cpp // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #include "backends/llvm.h" #include "backends/interp.h" namespace backend { Backend* Backend::getBackendFromOption(BackendOption opt, CompiledData& cd, const std::vector& in, const std::string& out) { switch(opt) { case BackendOption::LLVM: return new LLVMBackend(cd, in, out); case BackendOption::Interpreter: return new FIRInterpBackend(cd, in, out); case BackendOption::Assembly_x64: return new x64Backend(cd, in, out); case BackendOption::None: return nullptr; case BackendOption::Invalid: default: _error_and_exit("invalid backend\n"); } } std::string capabilitiesToString(BackendCaps::Capabilities caps) { std::vector list; if(caps & BackendCaps::EmitAssembly) list.push_back("'emit assembly'"); if(caps & BackendCaps::EmitObject) list.push_back("'emit object file'"); if(caps & BackendCaps::EmitProgram) list.push_back("'emit compiled program'"); if(caps & BackendCaps::JIT) list.push_back("'JIT'"); if(list.size() == 1) { return list.front(); } else if(list.size() == 2) { return list[0] + " and " + list[1]; } else { std::string ret; for(size_t i = 0; i < list.size() - 1; i++) ret += list[i] + ", "; ret += "and " + list.back(); return ret; } } } ================================================ FILE: source/backend/interp/driver.cpp ================================================ // driver.cpp // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. #include #include "defs.h" #include "backend.h" #include "frontend.h" #include "platform.h" #include "ir/interp.h" #include "ir/module.h" #include "backends/interp.h" namespace backend { template static void _printTiming(T ts, const std::string& thing) { if(frontend::getPrintProfileStats()) { auto dur = std::chrono::high_resolution_clock::now() - ts; auto ms = static_cast(dur.count()) / 1000000.0; printf("%s took %.1f ms%s\n", thing.c_str(), ms, ms > 3000 ? strprintf(" (aka %.2f s)", ms / 1000.0).c_str() : ""); } } using namespace fir; using namespace fir::interp; FIRInterpBackend::FIRInterpBackend(CompiledData& dat, const std::vector& inputs, const std::string& output) : Backend(BackendCaps::JIT, dat, inputs, output) { platform::compiler::performSelfDlOpen(); } FIRInterpBackend::~FIRInterpBackend() { if(this->is) delete this->is; } std::string FIRInterpBackend::str() { return "FIR Interpreter"; } void FIRInterpBackend::performCompilation() { this->is = new InterpState(this->compiledData.module); this->is->initialise(/* runGlobalInit:*/ true); // it suffices to compile just the entry function. this->is->compileFunction(this->compiledData.module->getEntryFunction()); } void FIRInterpBackend::optimiseProgram() { // nothing. } void FIRInterpBackend::writeOutput() { if(auto entryfn = this->compiledData.module->getEntryFunction(); entryfn) { auto ts = std::chrono::high_resolution_clock::now(); auto f = this->is->compiledFunctions[entryfn]; // add arguments if necessary, i guess. // just make null values. std::vector args; for(auto a : entryfn->getArguments()) args.push_back(this->is->makeValue(a)); this->is->runFunction(f, args); _printTiming(ts, "interp"); } else { error("interp: no entry function, cannot run!"); } } } ================================================ FILE: source/backend/llvm/jit.cpp ================================================ // jit.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "errors.h" #include "backends/llvm.h" #ifdef _MSC_VER #pragma warning(push, 0) #pragma warning(disable: 4267) #pragma warning(disable: 4244) #else #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" #endif #include "llvm/Analysis/Passes.h" #include "llvm/Transforms/Scalar.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/Transforms/Scalar/GVN.h" #include "llvm/Transforms/InstCombine/InstCombine.h" #ifdef _MSC_VER #pragma warning(pop) #else #pragma GCC diagnostic pop #endif static std::string dealWithLLVMError(const llvm::Error& err) { std::string str; auto out = llvm::raw_string_ostream(str); out << err; return out.str(); } namespace backend { LLVMJit::LLVMJit(llvm::orc::JITTargetMachineBuilder JTMB, llvm::DataLayout DL) : ObjectLayer(ES, []() { return std::make_unique(); }), CompileLayer(ES, ObjectLayer, std::make_unique(std::move(JTMB))), OptimiseLayer(ES, CompileLayer, optimiseModule), DL(std::move(DL)), Mangle(ES, this->DL), Ctx(std::make_unique()), dylib(ES.createJITDylib("").get()) { llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); dylib.addGenerator(llvm::cantFail( llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(DL.getGlobalPrefix()))); // dunno who's bright idea it was to match symbol flags *EXACTLY* instead of something more sane ObjectLayer.setOverrideObjectFlagsWithResponsibilityFlags(true); ObjectLayer.setAutoClaimResponsibilityForObjectSymbols(true); } void LLVMJit::addModule(std::unique_ptr mod) { // store it first lest it get stolen away auto modIdent = mod->getModuleIdentifier(); // llvm::Error::operator bool() returns true if there's an error. if(auto err = OptimiseLayer.add(this->dylib, llvm::orc::ThreadSafeModule(std::move(mod), Ctx)); err) error("llvm: failed to add module '%s': %s", modIdent, dealWithLLVMError(err)); } llvm::JITEvaluatedSymbol LLVMJit::findSymbol(const std::string& name) { if(auto ret = ES.lookup({ &this->dylib }, Mangle(name)); !ret) error("llvm: failed to find symbol '%s': %s", name, dealWithLLVMError(ret.takeError())); else return ret.get(); } LLVMJit* LLVMJit::create() { auto JTMB = llvm::orc::JITTargetMachineBuilder::detectHost(); if(!JTMB) error("llvm: failed to detect host", dealWithLLVMError(JTMB.takeError())); auto DL = JTMB->getDefaultDataLayoutForTarget(); if(!DL) error("llvm: failed to get data layout", dealWithLLVMError(DL.takeError())); return new LLVMJit(std::move(*JTMB), std::move(*DL)); } llvm::Expected LLVMJit::optimiseModule(llvm::orc::ThreadSafeModule TSM, const llvm::orc::MaterializationResponsibility& R) { #if 0 // Create a function pass manager. auto FPM = llvm::make_unique(TSM.getModule()); // Add some optimizations. FPM->add(llvm::createInstructionCombiningPass()); FPM->add(llvm::createReassociatePass()); FPM->add(llvm::createGVNPass()); FPM->add(llvm::createCFGSimplificationPass()); FPM->doInitialization(); // Run the optimizations over all functions in the module being added to // the JIT. for(auto& F : *TSM.getModule()) FPM->run(F); #endif return TSM; } llvm::JITTargetAddress LLVMJit::getSymbolAddress(const std::string& name) { return this->findSymbol(name).getAddress(); } } ================================================ FILE: source/backend/llvm/linker.cpp ================================================ // linker.cpp // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #ifndef __STDC_CONSTANT_MACROS #define __STDC_CONSTANT_MACROS #endif #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS #endif #include #ifdef _MSC_VER #pragma warning(push, 0) #pragma warning(disable: 4267) #pragma warning(disable: 4244) #else #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" #endif #include "llvm/IR/Verifier.h" #include "llvm/IR/IRBuilder.h" #include "llvm/Support/Host.h" #include "llvm/Linker/Linker.h" #include "llvm/Transforms/IPO.h" #include "llvm/IR/LLVMContext.h" #include "llvm/Analysis/Passes.h" #include "llvm/Transforms/Utils.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Target/TargetMachine.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/ExecutionEngine/MCJIT.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/DynamicLibrary.h" #include "llvm/Transforms/Scalar/Scalarizer.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/Transforms/InstCombine/InstCombine.h" #ifdef _MSC_VER #pragma warning(pop) #else #pragma GCC diagnostic pop #endif #include #include #include #include #include #include "ir/type.h" #include "ir/value.h" #include "ir/module.h" #include "ir/irbuilder.h" #include "frontend.h" #include "backends/llvm.h" #include "tinyprocesslib/tinyprocess.h" static llvm::LLVMContext globalContext; template static void _printTiming(T ts, const std::string& thing) { if(frontend::getPrintProfileStats()) { auto dur = std::chrono::high_resolution_clock::now() - ts; auto ms = static_cast(dur.count()) / 1000000.0; printf("%s took %.1f ms%s\n", thing.c_str(), ms, ms > 3000 ? strprintf(" (aka %.2f s)", ms / 1000.0).c_str() : ""); } } namespace backend { llvm::LLVMContext& LLVMBackend::getLLVMContext() { return globalContext; } LLVMBackend::LLVMBackend(CompiledData& dat, const std::vector& inputs, const std::string& output) : Backend(BackendCaps::EmitAssembly | BackendCaps::EmitObject | BackendCaps::EmitProgram | BackendCaps::JIT, dat, inputs, output) { } std::string LLVMBackend::str() { return "LLVM"; } void LLVMBackend::performCompilation() { auto ts = std::chrono::high_resolution_clock::now(); llvm::InitializeNativeTarget(); auto mainModule = this->translateFIRtoLLVM(this->compiledData.module); if(this->compiledData.module->getEntryFunction()) this->entryFunction = mainModule->getFunction(this->compiledData.module->getEntryFunction()->getName().mangled()); this->linkedModule = std::unique_ptr(mainModule); // ok, move some shit into here because llvm is fucking retarded this->setupTargetMachine(); this->linkedModule->setDataLayout(this->targetMachine->createDataLayout()); _printTiming(ts, "llvm translation"); } void LLVMBackend::optimiseProgram() { auto ts = std::chrono::high_resolution_clock::now(); llvm::legacy::PassManager fpm = llvm::legacy::PassManager(); fpm.add(llvm::createDeadInstEliminationPass()); fpm.add(llvm::createDeadCodeEliminationPass()); if(frontend::getOptLevel() > OptimisationLevel::Debug) { // mem2reg is based, because it changes inefficient load-store branches into more efficient phi-nodes (at least more efficient // in terms of optimisation potential) fpm.add(llvm::createPromoteMemoryToRegisterPass()); fpm.add(llvm::createMergedLoadStoreMotionPass()); fpm.add(llvm::createInstructionCombiningPass()); fpm.add(llvm::createConstantPropagationPass()); fpm.add(llvm::createScalarizerPass()); } if(frontend::getOptLevel() > OptimisationLevel::None) { fpm.add(llvm::createReassociatePass()); fpm.add(llvm::createCFGSimplificationPass()); // hmm. // fuck it, turn everything on. fpm.add(llvm::createConstantHoistingPass()); fpm.add(llvm::createLICMPass()); fpm.add(llvm::createDelinearizationPass()); fpm.add(llvm::createFlattenCFGPass()); fpm.add(llvm::createScalarizerPass()); fpm.add(llvm::createSinkingPass()); fpm.add(llvm::createDeadStoreEliminationPass()); fpm.add(llvm::createMemCpyOptPass()); fpm.add(llvm::createSCCPPass()); fpm.add(llvm::createTailCallEliminationPass()); } if(frontend::getOptLevel() > OptimisationLevel::Minimal) { fpm.add(llvm::createAggressiveDCEPass()); // module-level stuff fpm.add(llvm::createMergeFunctionsPass()); fpm.add(llvm::createLoopSimplifyPass()); } fpm.run(*this->linkedModule); _printTiming(ts, "llvm opt"); if(frontend::getPrintLLVMIR()) this->linkedModule->print(llvm::outs(), 0); } void LLVMBackend::writeOutput() { auto ts = std::chrono::high_resolution_clock::now(); if(llvm::verifyModule(*this->linkedModule, &llvm::errs())) { fprintf(stderr, "\n\n"); this->linkedModule->print(llvm::errs(), 0); BareError::make("llvm: module verification failed")->postAndQuit(); } std::string oname; if(this->outputFilename.empty()) { auto base = this->linkedModule->getModuleIdentifier(); if(frontend::getOutputMode() == ProgOutputMode::ObjectFile) oname = platform::compiler::getObjectFileName(base); else oname = platform::compiler::getExecutableName(base); } else { oname = this->outputFilename; } if(frontend::getOutputMode() == ProgOutputMode::RunJit) { std::string modname = ("llvm-jit-" + this->linkedModule->getModuleIdentifier()); const char* argv = modname.c_str(); auto entry = this->getEntryFunctionFromJIT(); _printTiming(ts, "llvm jit"); printf("\n"); iceAssert(this->jitInstance); entry(1, &argv); delete this->jitInstance; } else if(frontend::getOutputMode() == ProgOutputMode::LLVMBitcode) { std::error_code e; llvm::sys::fs::OpenFlags of = static_cast(0); llvm::raw_fd_ostream rso(oname.c_str(), e, of); llvm::WriteBitcodeToFile(*this->linkedModule.get(), rso); rso.close(); _printTiming(ts, "writing bitcode file"); } else { if(frontend::getOutputMode() != ProgOutputMode::ObjectFile && !this->compiledData.module->getEntryFunction()) { error("llvm: no entry function marked, a program cannot be compiled"); } llvm::SmallVector buffer; { auto bufferStream = std::make_unique(buffer); llvm::raw_pwrite_stream* rawStream = bufferStream.get(); { llvm::legacy::PassManager pm = llvm::legacy::PassManager(); targetMachine->addPassesToEmitFile(pm, *rawStream, nullptr, llvm::CodeGenFileType::CGFT_ObjectFile); pm.run(*this->linkedModule); } // flush and kill it. rawStream->flush(); } if(frontend::getOutputMode() == ProgOutputMode::ObjectFile) { // now memoryBuffer should contain the .object file std::ofstream objectOutput(oname, std::ios::binary | std::ios::out); objectOutput.write(buffer.data(), buffer.size_in_bytes()); objectOutput.close(); } else { std::string objname = platform::compiler::getObjectFileName(this->linkedModule->getModuleIdentifier()); std::ofstream objectOutput(objname, std::ios::binary | std::ios::out); objectOutput.write(buffer.data(), buffer.size_in_bytes()); objectOutput.close(); auto cmdline = platform::compiler::getCompilerCommandLine({ objname }, oname); // debuglogln("link cmdline:\n%s", cmdline); std::string sout; std::string serr; tinyproclib::Process proc(cmdline, "", [&sout](const char* bytes, size_t n) { sout = std::string(bytes, n); }, [&serr](const char* bytes, size_t n) { serr = std::string(bytes, n); }); // note: this waits for the process to finish. int status = proc.get_exit_status(); if(status != 0) { if(!sout.empty()) fprintf(stderr, "%s\n", sout.c_str()); if(!serr.empty()) fprintf(stderr, "%s\n", serr.c_str()); fprintf(stderr, "linker returned non-zero (status = %d), exiting\n", status); fprintf(stderr, "cmdline was: %s\n", cmdline.c_str()); exit(status); } } _printTiming(ts, "outputting exe/obj"); } } void LLVMBackend::setupTargetMachine() { llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmParser(); llvm::InitializeNativeTargetAsmPrinter(); llvm::Triple targetTriple; if(frontend::getOutputMode() == ProgOutputMode::RunJit || frontend::getParameter("targetarch").empty()) { targetTriple.setTriple(llvm::sys::getProcessTriple()); } else { targetTriple.setTriple(frontend::getParameter("targetarch")); } std::string err_str; const llvm::Target* theTarget = llvm::TargetRegistry::lookupTarget("", targetTriple, err_str); if(!theTarget) { error("llvm: failed in creating target: (wanted: '%s'); llvm error: %s\n", targetTriple.str(), err_str); } // get the mcmodel llvm::CodeModel::Model codeModel; auto getMcModelOfString = [](const std::string& s) -> llvm::CodeModel::Model { if(s == "kernel") return llvm::CodeModel::Kernel; if(s == "small") return llvm::CodeModel::Small; if(s == "medium") return llvm::CodeModel::Medium; if(s == "large") return llvm::CodeModel::Large; else error("llvm: invalid mcmodel '%s' (valid options: kernel, small, medium, or large)", s); }; auto getDefaultCodeModelForTarget = [](const llvm::Triple& triple) -> llvm::CodeModel::Model { if(triple.isArch64Bit() && !triple.isOSDarwin() && !triple.isAndroid() && !(triple.isAArch64() && triple.isOSLinux())) { return llvm::CodeModel::Large; } else if(triple.isOSDarwin() && (frontend::getOutputMode() == ProgOutputMode::RunJit)) { // apparently, when we JIT on osx we need mcmodel=large // but when we are compiling, we need mcmodel=small!! // WTF? nobody on the internet seems to know, but this was determined experimentally. // if we use mcmodel=small when JIT-ing, we crash when running... return llvm::CodeModel::Large; } else { return llvm::CodeModel::Small; } }; if(auto mcm = frontend::getParameter("mcmodel"); !mcm.empty()) codeModel = getMcModelOfString(mcm); else codeModel = getDefaultCodeModelForTarget(targetTriple); llvm::TargetOptions targetOptions; llvm::Reloc::Model relocModel = llvm::Reloc::Model::Static; // todo: use dynamic no pic for dylibs?? idk if(frontend::getIsPositionIndependent()) relocModel = llvm::Reloc::Model::PIC_; this->targetMachine = theTarget->createTargetMachine(targetTriple.getTriple(), "", "", targetOptions, relocModel, codeModel, llvm::CodeGenOpt::Default); } EntryPoint_t LLVMBackend::getEntryFunctionFromJIT() { using namespace llvm::sys; platform::compiler::addLibrarySearchPaths(); // default libraries come with the correct prefix/extension for the platform already, but user ones do not. auto tolink = zfu::map(frontend::getLibrariesToLink(), [](auto lib) -> auto { return platform::compiler::getSharedLibraryName(lib); }) + platform::compiler::getDefaultSharedLibraries(); for(auto lib : tolink) { std::string err; auto dl = DynamicLibrary::getPermanentLibrary(lib.c_str(), &err); if(!dl.isValid()) error("llvm: failed to load library '%s', dlopen failed with error:\n%s", lib, err); } for(auto fw : frontend::getFrameworksToLink()) { auto name = strprintf("%s.framework/%s", fw, fw); std::string err; auto dl = DynamicLibrary::getPermanentLibrary(name.c_str(), &err); if(!dl.isValid()) error("llvm: failed to load framework '%s', dlopen failed with error:\n%s", fw, err); } EntryPoint_t ret = 0; iceAssert(this->entryFunction); { auto name = this->entryFunction->getName().str(); this->jitInstance = LLVMJit::create(); this->jitInstance->addModule(std::move(this->linkedModule)); auto entryaddr = this->jitInstance->getSymbolAddress(name); ret = reinterpret_cast(entryaddr); iceAssert(ret && "failed to resolve entry function address"); } platform::compiler::restoreLibrarySearchPaths(); return ret; } } ================================================ FILE: source/backend/llvm/translator.cpp ================================================ // Translator.cpp // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #ifndef __STDC_CONSTANT_MACROS #define __STDC_CONSTANT_MACROS #endif #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS #endif #ifdef _MSC_VER #pragma warning(push, 0) #else #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" #endif #include "llvm/IR/Verifier.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" #ifdef _MSC_VER #pragma warning(pop) #else #pragma GCC diagnostic pop #endif #include "gluecode.h" #include "ir/module.h" #include "ir/constant.h" #include "backends/llvm.h" #include #define SLICE_DATA_INDEX 0 #define SLICE_LENGTH_INDEX 1 #define SAA_DATA_INDEX 0 #define SAA_LENGTH_INDEX 1 #define SAA_CAPACITY_INDEX 2 #define SAA_REFCOUNTPTR_INDEX 3 #define ANY_TYPEID_INDEX 0 #define ANY_REFCOUNTPTR_INDEX 1 #define ANY_DATA_ARRAY_INDEX 2 namespace backend { static util::hash_map createdTypes; static std::map cachedConstants; inline std::string llvmTyToString(llvm::Type* t) { std::string str; llvm::raw_string_ostream rso(str); t->print(rso); return str; } inline std::string llvmToString(llvm::Value* t) { std::string str; llvm::raw_string_ostream rso(str); t->print(rso); return str; } static llvm::Type* getNativeWordTy() { auto& gc = LLVMBackend::getLLVMContext(); return llvm::IntegerType::getIntNTy(gc, static_cast(fir::getNativeWordSizeInBits())); } static llvm::Type* typeToLlvm(fir::Type* type, llvm::Module* mod) { auto& gc = LLVMBackend::getLLVMContext(); if(type->isPrimitiveType()) { fir::PrimitiveType* pt = type->toPrimitiveType(); // signed/unsigned is lost. if(pt->isIntegerType()) { return llvm::IntegerType::getIntNTy(gc, static_cast(pt->getIntegerBitWidth())); } else if(pt->isFloatingPointType()) { if(pt->getFloatingPointBitWidth() == 32) return llvm::Type::getFloatTy(gc); else if(pt->getFloatingPointBitWidth() == 64) return llvm::Type::getDoubleTy(gc); else if(pt->getFloatingPointBitWidth() == 80) return llvm::Type::getX86_FP80Ty(gc); else if(pt->getFloatingPointBitWidth() == 128) return llvm::Type::getFP128Ty(gc); error("llvm: what"); } else { error("llvm: what"); } } else if(type->isStructType()) { fir::StructType* st = type->toStructType(); if(createdTypes.find(st->getTypeName()) != createdTypes.end()) return createdTypes[st->getTypeName()]; // to allow recursion, declare the type first. createdTypes[st->getTypeName()] = llvm::StructType::create(gc, st->getTypeName().mangled()); std::vector lmems; for(auto a : st->getElements()) lmems.push_back(typeToLlvm(a, mod)); createdTypes[st->getTypeName()]->setBody(lmems, st->isPackedStruct()); return createdTypes[st->getTypeName()]; } else if(type->isClassType()) { fir::ClassType* ct = type->toClassType(); if(createdTypes.find(ct->getTypeName()) != createdTypes.end()) return createdTypes[ct->getTypeName()]; // to allow recursion, declare the type first. createdTypes[ct->getTypeName()] = llvm::StructType::create(gc, ct->getTypeName().mangled()); std::vector lmems = zfu::map(ct->getAllElementsIncludingBase(), [&mod](auto t) -> auto { return typeToLlvm(t, mod); }); // insert the vtable at the front. if(ct->getVirtualMethodCount() > 0) lmems.insert(lmems.begin(), llvm::Type::getInt8PtrTy(gc)); createdTypes[ct->getTypeName()]->setBody(lmems); return createdTypes[ct->getTypeName()]; } else if(type->isTupleType()) { fir::TupleType* tt = type->toTupleType(); std::vector lmems; for(auto a : tt->getElements()) lmems.push_back(typeToLlvm(a, mod)); return llvm::StructType::get(gc, lmems); } else if(type->isFunctionType()) { fir::FunctionType* ft = type->toFunctionType(); std::vector largs; for(auto a : ft->getArgumentTypes()) largs.push_back(typeToLlvm(a, mod)); //! note(workaround): THIS IS A HACK. // we *ALWAYS* return a pointer to function, because llvm is stupid. // when we create an llvm::Function using this type, we always dereference the pointer type. // however, everywhere else (eg. function variables, parameters, etc.) we need pointers, because // llvm doesn't let FunctionType be a raw type (of a variable or param), but i'll let fir be less stupid, // so it transparently works without fir having to need pointers. return llvm::FunctionType::get(typeToLlvm(ft->getReturnType(), mod), largs, ft->isCStyleVarArg())->getPointerTo(); } else if(type->isArrayType()) { fir::ArrayType* at = type->toArrayType(); return llvm::ArrayType::get(typeToLlvm(at->getElementType(), mod), at->getArraySize()); } else if(type->isPointerType() || type->isNullType()) { if(type == fir::Type::getVoidPtr() || type->isNullType()) return llvm::Type::getInt8PtrTy(gc); else return typeToLlvm(type->getPointerElementType(), mod)->getPointerTo(); } else if(type->isVoidType()) { return llvm::Type::getVoidTy(gc); } else if(type->isDynamicArrayType()) { fir::DynamicArrayType* llat = type->toDynamicArrayType(); std::vector mems(4); mems[SAA_DATA_INDEX] = typeToLlvm(llat->getElementType()->getPointerTo(), mod); mems[SAA_LENGTH_INDEX] = getNativeWordTy(); mems[SAA_CAPACITY_INDEX] = getNativeWordTy(); mems[SAA_REFCOUNTPTR_INDEX] = getNativeWordTy()->getPointerTo(); return llvm::StructType::get(gc, mems, false); } else if(type->isStringType()) { llvm::Type* i8ptrtype = llvm::Type::getInt8PtrTy(gc); auto id = fir::Name::obfuscate("string", fir::NameKind::Type); if(createdTypes.find(id) != createdTypes.end()) return createdTypes[id]; std::vector mems(4); mems[SAA_DATA_INDEX] = i8ptrtype; mems[SAA_LENGTH_INDEX] = getNativeWordTy(); mems[SAA_CAPACITY_INDEX] = getNativeWordTy(); mems[SAA_REFCOUNTPTR_INDEX] = getNativeWordTy()->getPointerTo(); auto str = llvm::StructType::create(gc, id.mangled()); str->setBody(mems); return createdTypes[id] = str; } else if(type->isArraySliceType()) { fir::ArraySliceType* slct = type->toArraySliceType(); std::vector mems(2); mems[SLICE_DATA_INDEX] = typeToLlvm(slct->getElementType()->getPointerTo(), mod); mems[SLICE_LENGTH_INDEX] = getNativeWordTy(); return llvm::StructType::get(gc, mems, false); } else if(type->isBoolType()) { return llvm::Type::getInt1Ty(gc); } else if(type->isRangeType()) { auto id = fir::Name::obfuscate("range", fir::NameKind::Type); if(createdTypes.find(id) != createdTypes.end()) return createdTypes[id]; auto str = llvm::StructType::create(gc, id.mangled()); str->setBody({ getNativeWordTy(), getNativeWordTy(), getNativeWordTy() }); return createdTypes[id] = str; } else if(type->isEnumType()) { std::vector mems; mems.push_back(getNativeWordTy()); mems.push_back(typeToLlvm(type->toEnumType()->getCaseType(), mod)); return llvm::StructType::get(gc, mems, false); } else if(type->isAnyType()) { llvm::Type* arrtype = llvm::ArrayType::get(llvm::Type::getInt8Ty(gc), BUILTIN_ANY_DATA_BYTECOUNT); auto id = fir::Name::obfuscate("any", fir::NameKind::Type); if(createdTypes.find(id) != createdTypes.end()) return createdTypes[id]; auto str = llvm::StructType::create(gc, id.mangled()); // typeid (+ highest-bit-mask), refcount, data. str->setBody({ getNativeWordTy(), getNativeWordTy()->getPointerTo(), arrtype }); return createdTypes[id] = str; } else if(type->isUnionType()) { auto ut = type->toUnionType(); if(createdTypes.find(ut->getTypeName()) != createdTypes.end()) return createdTypes[ut->getTypeName()]; auto dl = llvm::DataLayout(mod); size_t maxSz = 0; for(auto v : ut->getVariants()) { if(!v.second->getInteriorType()->isVoidType()) maxSz = std::max(maxSz, static_cast(dl.getTypeAllocSize(typeToLlvm(v.second->getInteriorType(), mod)))); } if(maxSz > 0) { createdTypes[ut->getTypeName()] = llvm::StructType::create(gc, { getNativeWordTy(), llvm::ArrayType::get(llvm::Type::getInt8Ty(gc), maxSz) }, ut->getTypeName().mangled()); } else { createdTypes[ut->getTypeName()] = llvm::StructType::create(gc, { getNativeWordTy() }, ut->getTypeName().mangled()); } return createdTypes[ut->getTypeName()]; } else if(type->isRawUnionType()) { auto ut = type->toRawUnionType(); if(createdTypes.find(ut->getTypeName()) != createdTypes.end()) return createdTypes[ut->getTypeName()]; auto dl = llvm::DataLayout(mod); size_t maxSz = 0; for(auto v : ut->getVariants()) maxSz = std::max(maxSz, static_cast(dl.getTypeAllocSize(typeToLlvm(v.second, mod)))); iceAssert(maxSz > 0); createdTypes[ut->getTypeName()] = llvm::StructType::create(gc, { llvm::IntegerType::getIntNTy(gc, static_cast(maxSz * CHAR_BIT)) }, ut->getTypeName().mangled()); return createdTypes[ut->getTypeName()]; } else if(type->isPolyPlaceholderType()) { error("llvm: unfulfilled polymorphic placeholder type '%s'", type); } else { error("llvm: unimplememented type '%s' for LLVM backend", type); } } static llvm::Function* translateFunctionDecl(fir::Function* ffn, util::hash_map& valueMap, llvm::Module* mod) { if(auto it = valueMap.find(ffn->id); it != valueMap.end()) return llvm::cast(it->second); llvm::GlobalValue::LinkageTypes link; switch(ffn->linkageType) { case fir::LinkageType::External: link = llvm::GlobalValue::LinkageTypes::ExternalLinkage; break; case fir::LinkageType::Internal: link = llvm::GlobalValue::LinkageTypes::InternalLinkage; break; case fir::LinkageType::ExternalWeak: link = llvm::GlobalValue::LinkageTypes::ExternalWeakLinkage; break; default: error("llvm: enotsup"); } llvm::FunctionType* ftype = llvm::cast(typeToLlvm(ffn->getType(), mod)->getPointerElementType()); llvm::Function* func = llvm::Function::Create(ftype, link, ffn->getName().mangled(), mod); if(ffn->isAlwaysInlined()) func->addFnAttr(llvm::Attribute::AttrKind::AlwaysInline); valueMap[ffn->id] = func; size_t i = 0; for(auto it = func->arg_begin(); it != func->arg_end(); it++, i++) valueMap[ffn->getArguments()[i]->id] = it; for(auto b : ffn->getBlockList()) { llvm::BasicBlock* bb = llvm::BasicBlock::Create(LLVMBackend::getLLVMContext(), b->getName().mangled(), func); valueMap[b->id] = bb; } return func; } static llvm::Constant* constToLlvm(fir::ConstantValue* fc, util::hash_map& valueMap, llvm::Module* mod) { iceAssert(fc); auto ret = cachedConstants[fc]; if(ret) return ret; if(auto ci = dcast(fir::ConstantInt, fc)) { llvm::Type* it = typeToLlvm(fc->getType(), mod); if(ci->getType()->toPrimitiveType()->isSigned()) { return cachedConstants[fc] = llvm::ConstantInt::getSigned(it, ci->getSignedValue()); } else { return cachedConstants[fc] = llvm::ConstantInt::get(it, ci->getUnsignedValue()); } } else if(auto cf = dcast(fir::ConstantFP, fc)) { llvm::Type* it = typeToLlvm(fc->getType(), mod); return cachedConstants[fc] = llvm::ConstantFP::get(it, cf->getValue()); } else if(dcast(fir::ConstantNumber, fc)) { error("cannot"); } else if(auto cc = dcast(fir::ConstantBool, fc)) { llvm::Type* ct = typeToLlvm(fc->getType(), mod); return cachedConstants[fc] = llvm::ConstantInt::get(ct, cc->getValue()); } else if(auto cbc = dcast(fir::ConstantBitcast, fc)) { llvm::Type* t = typeToLlvm(cbc->getType(), mod); return cachedConstants[fc] = llvm::ConstantExpr::getBitCast(constToLlvm(cbc->getValue(), valueMap, mod), t); } else if(auto ca = dcast(fir::ConstantArray, fc)) { auto arrt = llvm::cast(typeToLlvm(ca->getType(), mod)); std::vector vals; vals.reserve(ca->getValues().size()); for(auto con : ca->getValues()) { auto c = constToLlvm(con, valueMap, mod); if(c->getType() != arrt->getArrayElementType()) { error("llvm: expected type '%s' in const array (%d), found '%s'", llvmTyToString(arrt->getArrayElementType()), ca->id, llvmToString(c)); // c = llvm::ConstantExpr::getBitCast(c, arrt->getArrayElementType()); } vals.push_back(c); } return cachedConstants[fc] = llvm::ConstantArray::get(arrt, vals); } else if(auto ct = dcast(fir::ConstantTuple, fc)) { std::vector vals; vals.reserve(ct->getValues().size()); for(auto v : ct->getValues()) vals.push_back(constToLlvm(v, valueMap, mod)); return cachedConstants[fc] = llvm::ConstantStruct::getAnon(LLVMBackend::getLLVMContext(), vals); } else if(auto cec = dcast(fir::ConstantEnumCase, fc)) { auto ty = typeToLlvm(cec->getType(), mod); iceAssert(ty->isStructTy()); return cachedConstants[fc] = llvm::ConstantStruct::get(llvm::cast(ty), constToLlvm(cec->getIndex(), valueMap, mod), constToLlvm(cec->getValue(), valueMap, mod)); } else if(dcast(fir::ConstantCharSlice, fc) || dcast(fir::ConstantDynamicString, fc)) { bool wasDynStr = false; std::string str; if(auto ccs = dcast(fir::ConstantCharSlice, fc)) str = ccs->getValue(); else if(auto cds = dcast(fir::ConstantDynamicString, fc)) wasDynStr = true, str = cds->getValue(); llvm::Constant* cstr = llvm::ConstantDataArray::getString(LLVMBackend::getLLVMContext(), str, true); llvm::GlobalVariable* gv = new llvm::GlobalVariable(*mod, cstr->getType(), true, llvm::GlobalValue::LinkageTypes::InternalLinkage, cstr, "_FV_STR_" + std::to_string(fc->id)); auto zconst = llvm::ConstantInt::get(getNativeWordTy(), 0); std::vector indices = { zconst, zconst }; llvm::Constant* gepd = llvm::ConstantExpr::getGetElementPtr(gv->getType()->getPointerElementType(), gv, indices); auto len = llvm::ConstantInt::get(getNativeWordTy(), str.size()); iceAssert(gepd->getType() == llvm::Type::getInt8PtrTy(LLVMBackend::getLLVMContext())); iceAssert(len->getType() == getNativeWordTy()); fir::Type* ty = fir::Type::getCharSlice(false); std::vector mems = { gepd, len }; if(wasDynStr) { ty = fir::Type::getString(); // add -1 for the capacity and 0 for the refcountptr. mems.push_back(llvm::ConstantInt::get(getNativeWordTy(), static_cast(-1))); mems.push_back(zconst); } auto ret = llvm::ConstantStruct::get(llvm::cast(typeToLlvm(ty, mod)), mems); cachedConstants[fc] = ret; return ret; } else if(auto cas = dcast(fir::ConstantArraySlice, fc)) { std::vector mems = { constToLlvm(cas->getData(), valueMap, mod), constToLlvm(cas->getLength(), valueMap, mod) }; auto ret = llvm::ConstantStruct::get(llvm::cast(typeToLlvm(cas->getType(), mod)), mems); return cachedConstants[fc] = ret; } else if(auto cda = dcast(fir::ConstantDynamicArray, fc)) { if(cda->getArray()) { llvm::Constant* constArray = constToLlvm(cda->getArray(), valueMap, mod); iceAssert(constArray); // don't make it immutable. this probably puts the global variable in the .data segment, instead of the // .rodata/.rdata segment. // this allows us to modify it, eg. // var foo = [ 1, 2, 3 ] // foo[0] = 4 // of course, since capacity == -1, the moment we try to like append or something, // we get back new heap memory llvm::GlobalVariable* tmpglob = new llvm::GlobalVariable(*mod, constArray->getType(), false, llvm::GlobalValue::LinkageTypes::InternalLinkage, constArray, "_FV_ARR_" + std::to_string(cda->id)); auto zconst = llvm::ConstantInt::get(getNativeWordTy(), 0); std::vector indices = { zconst, zconst }; llvm::Constant* gepd = llvm::ConstantExpr::getGetElementPtr(tmpglob->getType()->getPointerElementType(), tmpglob, indices); auto flen = fir::ConstantInt::getNative(cda->getArray()->getType()->toArrayType()->getArraySize()); auto fcap = fir::ConstantInt::getNative(-1); std::vector mems = { gepd, constToLlvm(flen, valueMap, mod), constToLlvm(fcap, valueMap, mod), zconst }; auto ret = llvm::ConstantStruct::get(llvm::cast(typeToLlvm(cda->getType(), mod)), mems); return cachedConstants[fc] = ret; } else { std::vector mems = { constToLlvm(cda->getData(), valueMap, mod), constToLlvm(cda->getLength(), valueMap, mod), constToLlvm(cda->getCapacity(), valueMap, mod), llvm::ConstantInt::get(getNativeWordTy(), 0) }; auto ret = llvm::ConstantStruct::get(llvm::cast(typeToLlvm(cda->getType(), mod)), mems); return cachedConstants[fc] = ret; } } else if(auto fn = dcast(fir::Function, fc)) { return translateFunctionDecl(fn, valueMap, mod); } else if(dcast(fir::ConstantStruct, fc)) { _error_and_exit("notsup const struct\n"); } else if(auto it = valueMap.find(fc->id); it != valueMap.end() && llvm::isa(it->second)) { return llvm::cast(it->second); } else { return cachedConstants[fc] = llvm::Constant::getNullValue(typeToLlvm(fc->getType(), mod)); } } llvm::Module* LLVMBackend::translateFIRtoLLVM(fir::Module* firmod) { auto& gc = LLVMBackend::getLLVMContext(); llvm::Module* module = new llvm::Module(firmod->getModuleName(), LLVMBackend::getLLVMContext()); llvm::IRBuilder<> builder(gc); createdTypes.clear(); cachedConstants.clear(); util::hash_map& valueMap = *(new util::hash_map()); auto decay = [&builder](fir::Value* fv, llvm::Value* lv) -> llvm::Value* { if(fv->islvalue()) return builder.CreateLoad(lv); else return lv; }; auto getValue = [&valueMap, &module, &firmod](fir::Value* fv) -> llvm::Value* { if(fir::GlobalVariable* gv = dcast(fir::GlobalVariable, fv)) { llvm::Value* lgv = valueMap[gv->id]; if(!lgv) error("llvm: failed to find var %d in mod %s\n", gv->id, firmod->getModuleName()); iceAssert(lgv); return lgv; } // we must do this because function now derives from constantvalue else if(dcast(fir::Function, fv)) { llvm::Value* ret = valueMap[fv->id]; if(!ret) error("llvm: !ret fn (id = %d)", fv->id); return ret; } else if(fir::ConstantValue* cv = dcast(fir::ConstantValue, fv)) { return constToLlvm(cv, valueMap, module); } else { llvm::Value* ret = valueMap[fv->id]; if(!ret) error("llvm: !ret (id = %d)", fv->id); return ret; } }; auto getUndecayedOperand = [&getValue](fir::Instruction* inst, size_t op) -> llvm::Value* { iceAssert(inst->operands.size() > op); fir::Value* fv = inst->operands[op]; return getValue(fv); }; auto getOperand = [&getValue, &decay](fir::Instruction* inst, size_t op) -> llvm::Value* { iceAssert(inst->operands.size() > op); fir::Value* fv = inst->operands[op]; return decay(fv, getValue(fv)); }; auto addValueToMap = [&valueMap](llvm::Value* v, fir::Value* fv) { iceAssert(v); // fprintf(stderr, "add id %d\n", fv->id); if(valueMap.find(fv->id) != valueMap.end()) error("llvm: already have value with id %d", fv->id); valueMap[fv->id] = v; // printf("adding value %d\n", fv->id); if(!v->getType()->isVoidTy()) v->setName(fv->getName().mangled()); }; static size_t strn = 0; for(auto string : firmod->_getGlobalStrings()) { std::string id = "_FV_STR" + std::to_string(strn); llvm::Constant* cstr = llvm::ConstantDataArray::getString(gc, string.first, true); llvm::Constant* gv = new llvm::GlobalVariable(*module, cstr->getType(), true, llvm::GlobalValue::LinkageTypes::InternalLinkage, cstr, id); auto zconst = llvm::ConstantInt::get(getNativeWordTy(), 0); std::vector ix { zconst, zconst }; gv = llvm::ConstantExpr::getInBoundsGetElementPtr(gv->getType()->getPointerElementType(), gv, ix); valueMap[string.second->id] = gv; strn++; } for(auto global : firmod->_getGlobals()) { llvm::Constant* initval = 0; llvm::Type* ty = typeToLlvm(global.second->getType(), module); if(global.second->getInitialValue() != 0) initval = constToLlvm(global.second->getInitialValue(), valueMap, module); else initval = llvm::Constant::getNullValue(ty); llvm::GlobalVariable* gv = new llvm::GlobalVariable(*module, ty, false, global.second->linkageType == fir::LinkageType::External ? llvm::GlobalValue::LinkageTypes::ExternalLinkage : llvm::GlobalValue::LinkageTypes::InternalLinkage, initval, global.first.mangled()); valueMap[global.second->id] = gv; } for(auto type : firmod->_getNamedTypes()) { // should just automatically create it. typeToLlvm(type.second, module); } for(auto intr : firmod->_getIntrinsicFunctions()) { llvm::Value* fn = 0; //* in LLVM 7, the intrinsics changed to no longer specify the alignment //* so, the arugments are: [ ptr, ptr, size, is_volatile ] if(intr.first.str() == "memcpy") { llvm::FunctionType* ft = llvm::FunctionType::get(llvm::Type::getVoidTy(gc), { llvm::Type::getInt8PtrTy(gc), llvm::Type::getInt8PtrTy(gc), getNativeWordTy(), llvm::Type::getInt1Ty(gc) }, false); fn = module->getOrInsertFunction(strprintf("llvm.memcpy.p0i8.p0i8.i%d", fir::getNativeWordSizeInBits()), ft).getCallee(); } else if(intr.first.str() == "memmove") { llvm::FunctionType* ft = llvm::FunctionType::get(llvm::Type::getVoidTy(gc), { llvm::Type::getInt8PtrTy(gc), llvm::Type::getInt8PtrTy(gc), getNativeWordTy(), llvm::Type::getInt1Ty(gc) }, false); fn = module->getOrInsertFunction(strprintf("llvm.memmove.p0i8.p0i8.i%d", fir::getNativeWordSizeInBits()), ft).getCallee(); } else if(intr.first.str() == "memset") { llvm::FunctionType* ft = llvm::FunctionType::get(llvm::Type::getVoidTy(gc), { llvm::Type::getInt8PtrTy(gc), llvm::Type::getInt8Ty(gc), getNativeWordTy(), llvm::Type::getInt1Ty(gc) }, false); fn = module->getOrInsertFunction(strprintf("llvm.memset.p0i8.i%d", fir::getNativeWordSizeInBits()), ft).getCallee(); } else if(intr.first.str() == "memcmp") { // in line with the rest, take 4 arguments. (this is our own "intrinsic") llvm::FunctionType* ft = llvm::FunctionType::get(llvm::Type::getInt32Ty(gc), { llvm::Type::getInt8PtrTy(gc), llvm::Type::getInt8PtrTy(gc), getNativeWordTy(), llvm::Type::getInt1Ty(gc) }, false); fn = llvm::Function::Create(ft, llvm::GlobalValue::LinkageTypes::InternalLinkage, "fir.intrinsic.memcmp", module); llvm::Function* func = llvm::cast(fn); iceAssert(func); // ok... now make the function, right here. { func->addFnAttr(llvm::Attribute::AttrKind::AlwaysInline); llvm::BasicBlock* entry = llvm::BasicBlock::Create(gc, "entry", func); builder.SetInsertPoint(entry); /* basically: int counter = 0; while(counter < size) { i8 c1 = s1[counter]; i8 c2 = s2[counter]; if(c1 != c2) return c1 - c2; counter++; } */ llvm::Value* res = builder.CreateAlloca(llvm::Type::getInt32Ty(gc)); llvm::Value* ptr1 = 0; llvm::Value* ptr2 = 0; llvm::Value* cmplen = 0; { // llvm is stupid. auto it = func->arg_begin(); ptr1 = it; it++; ptr2 = it; it++; cmplen = it; } auto zeroconst = llvm::ConstantInt::get(gc, llvm::APInt(64, 0, true)); auto zeroconst8 = llvm::ConstantInt::get(gc, llvm::APInt(8, 0, true)); llvm::Value* ctr = builder.CreateAlloca(getNativeWordTy()); builder.CreateStore(zeroconst, ctr); llvm::BasicBlock* loopcond = llvm::BasicBlock::Create(gc, "loopcond", func); llvm::BasicBlock* loopbody = llvm::BasicBlock::Create(gc, "loopbody", func); llvm::BasicBlock* merge = llvm::BasicBlock::Create(gc, "merge", func); // explicit branch to loopcond builder.CreateBr(loopcond); builder.SetInsertPoint(loopcond); { // bounds check llvm::Value* cond = builder.CreateICmpSLT(builder.CreateLoad(ctr), cmplen); builder.CreateCondBr(cond, loopbody, merge); } builder.SetInsertPoint(loopbody); { llvm::Value* ctrval = builder.CreateLoad(ctr); llvm::Value* ch1 = builder.CreateLoad(builder.CreateInBoundsGEP(ptr1, ctrval)); llvm::Value* ch2 = builder.CreateLoad(builder.CreateInBoundsGEP(ptr2, ctrval)); llvm::Value* diff = builder.CreateSub(ch1, ch2); builder.CreateStore(builder.CreateIntCast(diff, llvm::Type::getInt32Ty(gc), false), res); builder.CreateStore(builder.CreateAdd(ctrval, llvm::ConstantInt::get(gc, llvm::APInt(64, 1, true))), ctr); builder.CreateCondBr(builder.CreateICmpEQ(diff, zeroconst8), loopcond, merge); } builder.SetInsertPoint(merge); { builder.CreateRet(builder.CreateLoad(res)); } } } else if(intr.first.name == "roundup_pow2") { llvm::FunctionType* ft = llvm::FunctionType::get(getNativeWordTy(), { getNativeWordTy() }, false); fn = llvm::Function::Create(ft, llvm::GlobalValue::LinkageTypes::InternalLinkage, "fir.intrinsic.roundup_pow2", module); llvm::Function* func = llvm::cast(fn); iceAssert(func); // ok... now make the function, right here. { func->addFnAttr(llvm::Attribute::AttrKind::AlwaysInline); llvm::BasicBlock* entry = llvm::BasicBlock::Create(gc, "entry", func); builder.SetInsertPoint(entry); /* basically: int num = arg; int ret = 1; while(num > 0) { num >>= 1 ret <<= 1; } return ret; */ llvm::Value* num = builder.CreateAlloca(getNativeWordTy()); llvm::Value* retval = builder.CreateAlloca(getNativeWordTy()); auto oneconst = llvm::ConstantInt::get(gc, llvm::APInt(64, 1, true)); auto zeroconst = llvm::ConstantInt::get(gc, llvm::APInt(64, 0, true)); builder.CreateStore(oneconst, retval); builder.CreateStore(func->arg_begin(), num); llvm::BasicBlock* loopcond = llvm::BasicBlock::Create(gc, "loopcond", func); llvm::BasicBlock* loopbody = llvm::BasicBlock::Create(gc, "loopbody", func); llvm::BasicBlock* merge = llvm::BasicBlock::Create(gc, "merge", func); // explicit branch to loopcond builder.CreateBr(loopcond); builder.SetInsertPoint(loopcond); { // bounds check llvm::Value* cond = builder.CreateICmpSGT(builder.CreateLoad(num), zeroconst); builder.CreateCondBr(cond, loopbody, merge); } builder.SetInsertPoint(loopbody); { llvm::Value* shifted = builder.CreateLShr(builder.CreateLoad(num), 1); builder.CreateStore(shifted, num); builder.CreateStore(builder.CreateShl(builder.CreateLoad(retval), 1), retval); builder.CreateBr(loopcond); } builder.SetInsertPoint(merge); { builder.CreateRet(builder.CreateLoad(retval)); } } } else { error("llvm: unknown intrinsic '%s'", intr.first.str()); } valueMap[intr.second->id] = fn; } // fprintf(stderr, "translating module %s\n", this->moduleName.c_str()); for(auto f : firmod->_getFunctions()) { translateFunctionDecl(f.second, valueMap, module); } #define DO_DUMP 0 #if DO_DUMP #define DUMP_INSTR(fmt, ...) (fprintf(stderr, fmt, ##__VA_ARGS__)) #else #define DUMP_INSTR(...) #endif for(auto fp : firmod->_getFunctions()) { fir::Function* ffn = fp.second; // if(isGenericInAnyWay(ffn->getType())) // continue; llvm::Function* func = module->getFunction(fp.second->getName().mangled()); iceAssert(func); DUMP_INSTR("%s%s", ffn->getBlockList().size() == 0 ? "declare " : "", ffn->getName().c_str()); if(ffn->getBlockList().size() > 0) { // print args DUMP_INSTR(" :: ("); size_t i = 0; for(auto arg : ffn->getArguments()) { DUMP_INSTR("%%%d :: %s", arg->id, arg->getType()->str().c_str()); i++; (void) arg; if(i != ffn->getArgumentCount()) { DUMP_INSTR(","); } } DUMP_INSTR(")"); } else { DUMP_INSTR(" :: %s\n", ffn->getType()->str().c_str()); } for(auto block : ffn->getBlockList()) { llvm::BasicBlock* bb = llvm::cast(valueMap[block->id]); builder.SetInsertPoint(bb); DUMP_INSTR("\n %s", ("(%" + std::to_string(block->id) + ") " + block->getName() + ":\n").c_str()); for(auto inst : block->getInstructions()) { DUMP_INSTR(" %s\n", inst->str().c_str()); // good god. switch(inst->opKind) { case fir::OpKind::Signed_Add: case fir::OpKind::Unsigned_Add: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateAdd(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Signed_Sub: case fir::OpKind::Unsigned_Sub: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateSub(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Signed_Mul: case fir::OpKind::Unsigned_Mul: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateMul(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Signed_Div: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateSDiv(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Signed_Mod: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateSRem(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Signed_Neg: { iceAssert(inst->operands.size() == 1); llvm::Value* a = getOperand(inst, 0); llvm::Value* ret = builder.CreateNeg(a); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Unsigned_Div: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateUDiv(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Unsigned_Mod: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateURem(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Floating_Add: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateFAdd(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Floating_Sub: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateFSub(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Floating_Mul: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateFMul(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Floating_Div: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateFDiv(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Floating_Mod: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateFRem(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Floating_Neg: { iceAssert(inst->operands.size() == 1); llvm::Value* a = getOperand(inst, 0); llvm::Value* ret = builder.CreateFNeg(a); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Floating_Truncate: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); fir::Type* ft = inst->operands[1]->getType(); llvm::Type* t = typeToLlvm(ft, module); llvm::Value* ret = builder.CreateFPTrunc(a, t); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Floating_Extend: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); fir::Type* ft = inst->operands[1]->getType(); llvm::Type* t = typeToLlvm(ft, module); llvm::Value* ret = builder.CreateFPExt(a, t); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Integer_ZeroExt: case fir::OpKind::Integer_Truncate: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); fir::Type* ft = inst->operands[1]->getType(); llvm::Type* t = typeToLlvm(ft, module); llvm::Value* ret = builder.CreateZExtOrTrunc(a, t); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::ICompare_Equal: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateICmpEQ(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::ICompare_NotEqual: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateICmpNE(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::ICompare_Greater: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = 0; if(inst->operands[0]->getType()->isSignedIntType() || inst->operands[1]->getType()->isSignedIntType()) ret = builder.CreateICmpSGT(a, b); else ret = builder.CreateICmpUGT(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::ICompare_Less: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = 0; if(inst->operands[0]->getType()->isSignedIntType() || inst->operands[1]->getType()->isSignedIntType()) ret = builder.CreateICmpSLT(a, b); else ret = builder.CreateICmpULT(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::ICompare_GreaterEqual: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = 0; if(inst->operands[0]->getType()->isSignedIntType() || inst->operands[1]->getType()->isSignedIntType()) ret = builder.CreateICmpSGE(a, b); else ret = builder.CreateICmpUGE(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::ICompare_LessEqual: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = 0; if(inst->operands[0]->getType()->isSignedIntType() || inst->operands[1]->getType()->isSignedIntType()) ret = builder.CreateICmpSLE(a, b); else ret = builder.CreateICmpULE(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::FCompare_Equal_ORD: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateFCmpOEQ(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::FCompare_Equal_UNORD: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateFCmpUEQ(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::FCompare_NotEqual_ORD: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateFCmpONE(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::FCompare_NotEqual_UNORD: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateFCmpUNE(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::FCompare_Greater_ORD: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateFCmpOGT(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::FCompare_Greater_UNORD: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateFCmpUGT(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::FCompare_Less_ORD: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateFCmpOLT(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::FCompare_Less_UNORD: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateFCmpULT(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::FCompare_GreaterEqual_ORD: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateFCmpOGE(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::FCompare_GreaterEqual_UNORD: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateFCmpUGE(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::FCompare_LessEqual_ORD: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateFCmpOLE(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::FCompare_LessEqual_UNORD: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateFCmpULE(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::ICompare_Multi: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); bool sgn = inst->operands[0]->getType()->isSignedIntType() || inst->operands[1]->getType()->isSignedIntType(); llvm::Value* r1 = 0; if(sgn) r1 = builder.CreateICmpSGE(a, b); else r1 = builder.CreateICmpUGE(a, b); llvm::Value* r2 = 0; if(sgn) r2 = builder.CreateICmpSLE(a, b); else r2 = builder.CreateICmpULE(a, b); r1 = builder.CreateIntCast(r1, getNativeWordTy(), false); r2 = builder.CreateIntCast(r2, getNativeWordTy(), false); llvm::Value* ret = builder.CreateSub(r1, r2); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::FCompare_Multi: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* r1 = builder.CreateFCmpOGE(a, b); llvm::Value* r2 = builder.CreateFCmpOLE(a, b); r1 = builder.CreateIntCast(r1, getNativeWordTy(), false); r2 = builder.CreateIntCast(r2, getNativeWordTy(), false); llvm::Value* ret = builder.CreateSub(r1, r2); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Bitwise_Not: { iceAssert(inst->operands.size() == 1); llvm::Value* a = getOperand(inst, 0); llvm::Value* ret = builder.CreateNot(a); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Bitwise_Xor: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateXor(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Bitwise_Arithmetic_Shr: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateAShr(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Bitwise_Logical_Shr: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateLShr(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Bitwise_Shl: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateShl(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Bitwise_And: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateAnd(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Bitwise_Or: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* ret = builder.CreateOr(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Value_WritePtr: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); if(a->getType() != b->getType()->getPointerElementType()) error("llvm: cannot store '%s' into '%s'", inst->operands[0]->getType(), inst->operands[1]->getType()); llvm::Value* ret = builder.CreateStore(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Value_ReadPtr: { iceAssert(inst->operands.size() == 1); llvm::Value* a = getOperand(inst, 0); llvm::Value* ret = builder.CreateLoad(a); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Value_CreatePHI: { iceAssert(inst->operands.size() == 1); llvm::Type* t = typeToLlvm(inst->operands[0]->getType(), module); auto phi = dcast(fir::PHINode, inst->realOutput); iceAssert(phi); llvm::PHINode* ret = builder.CreatePHI(t, static_cast(phi->getValues().size())); for(auto v : phi->getValues()) { ret->addIncoming(decay(v.second, getValue(v.second)), llvm::cast(decay(v.first, getValue(v.first))) ); } addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Value_CallFunction: { iceAssert(inst->operands.size() >= 1); fir::Function* fn = dcast(fir::Function, inst->operands[0]); iceAssert(fn); llvm::Function* a = llvm::cast(getUndecayedOperand(inst, 0)); std::vector args; std::vector fargs = inst->operands; for(size_t i = 1; i < fargs.size(); ++i) { args.push_back(decay(fargs[i], getValue(fargs[i]))); // args.back()->dump(); } // a->dump(); llvm::Value* ret = builder.CreateCall(a, args); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Value_CallFunctionPointer: { iceAssert(inst->operands.size() >= 1); llvm::Value* fn = getOperand(inst, 0); std::vector args; std::vector fargs = inst->operands; for(size_t i = 1; i < fargs.size(); ++i) args.push_back(decay(fargs[i], getValue(fargs[i]))); llvm::Type* lft = typeToLlvm(inst->operands.front()->getType(), module); iceAssert(lft->isPointerTy()); iceAssert(lft->getPointerElementType()->isFunctionTy()); llvm::FunctionType* ft = llvm::cast(lft->getPointerElementType()); iceAssert(ft); llvm::Value* ret = builder.CreateCall(ft, fn, args); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Value_CallVirtualMethod: { // args are: 0. classtype, 1. index, 2. functiontype, 3...N args auto clsty = inst->operands[0]->getType()->toClassType(); iceAssert(clsty); iceAssert(clsty->getVirtualMethodCount() > 0); std::vector args; for(size_t i = 3; i < inst->operands.size(); i++) args.push_back(decay(inst->operands[i], getValue(inst->operands[i]))); llvm::Value* vtable = builder.CreateLoad(builder.CreateStructGEP(typeToLlvm(clsty, module), args[0], 0)); vtable = builder.CreateBitOrPointerCast(vtable, llvm::ArrayType::get(llvm::FunctionType::get(llvm::Type::getVoidTy(gc), false)->getPointerTo(), clsty->getVirtualMethodCount())->getPointerTo()); auto fptr = builder.CreateConstInBoundsGEP2_32(vtable->getType()->getPointerElementType(), vtable, 0, static_cast(dcast(fir::ConstantInt, inst->operands[1])->getUnsignedValue())); auto ffty = inst->operands[2]->getType()->toFunctionType(); fptr = builder.CreateBitOrPointerCast(builder.CreateLoad(fptr), typeToLlvm(ffty, module)); llvm::FunctionType* ft = llvm::cast(typeToLlvm(ffty, module)->getPointerElementType()); iceAssert(ft); llvm::Value* ret = builder.CreateCall(ft, fptr, args); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Value_Return: { llvm::Value* ret = 0; if(inst->operands.size() == 0) { ret = builder.CreateRetVoid(); } else { iceAssert(inst->operands.size() == 1); llvm::Value* a = getOperand(inst, 0); ret = builder.CreateRet(a); } addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Branch_UnCond: { iceAssert(inst->operands.size() == 1); llvm::Value* a = getOperand(inst, 0); llvm::Value* ret = builder.CreateBr(llvm::cast(a)); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Branch_Cond: { iceAssert(inst->operands.size() == 3); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); llvm::Value* c = getOperand(inst, 2); llvm::Value* ret = builder.CreateCondBr(a, llvm::cast(b), llvm::cast(c)); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Cast_Bitcast: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); fir::Type* ft = inst->operands[1]->getType(); llvm::Type* t = typeToLlvm(ft, module); llvm::Value* ret = builder.CreateBitCast(a, t); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Cast_IntSize: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); fir::Type* ft = inst->operands[1]->getType(); llvm::Type* t = typeToLlvm(ft, module); llvm::Value* ret = builder.CreateIntCast(a, t, ft->isSignedIntType()); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Cast_Signedness: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); // no-op addValueToMap(a, inst->realOutput); break; } case fir::OpKind::Cast_FloatToInt: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); fir::Type* ft = inst->operands[1]->getType(); llvm::Type* t = typeToLlvm(ft, module); llvm::Value* ret = 0; if(ft->isSignedIntType()) ret = builder.CreateFPToSI(a, t); else ret = builder.CreateFPToUI(a, t); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Cast_IntToFloat: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); fir::Type* ft = inst->operands[1]->getType(); llvm::Type* t = typeToLlvm(ft, module); llvm::Value* ret = 0; if(inst->operands[0]->getType()->isSignedIntType()) ret = builder.CreateSIToFP(a, t); else ret = builder.CreateUIToFP(a, t); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Cast_PointerType: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); fir::Type* ft = inst->operands[1]->getType(); llvm::Type* t = typeToLlvm(ft, module); llvm::Value* ret = builder.CreatePointerCast(a, t); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Cast_PointerToInt: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); fir::Type* ft = inst->operands[1]->getType(); llvm::Type* t = typeToLlvm(ft, module); llvm::Value* ret = builder.CreatePtrToInt(a, t); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Cast_IntToPointer: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); fir::Type* ft = inst->operands[1]->getType(); llvm::Type* t = typeToLlvm(ft, module); llvm::Value* ret = builder.CreateIntToPtr(a, t); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Cast_IntSignedness: { // is no op. // since llvm does not differentiate signed and unsigned. iceAssert(inst->operands.size() == 2); llvm::Value* ret = getOperand(inst, 0); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Value_GetPointer: { // equivalent to GEP(ptr*, index) iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); iceAssert(!inst->operands[0]->getType()->isClassType() && !inst->operands[0]->getType()->isStructType()); llvm::Value* ret = builder.CreateGEP(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Value_GetGEP2: { // equivalent to GEP(ptr*, index) iceAssert(inst->operands.size() == 3); llvm::Value* a = getOperand(inst, 0); iceAssert(!inst->operands[0]->getType()->isClassType() && !inst->operands[0]->getType()->isStructType()); std::vector indices = { getOperand(inst, 1), getOperand(inst, 2) }; llvm::Value* ret = builder.CreateGEP(a, indices); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Misc_Sizeof: { iceAssert(inst->operands.size() == 1); llvm::Type* t = getOperand(inst, 0)->getType(); iceAssert(t); llvm::Value* gep = builder.CreateConstGEP1_64(llvm::ConstantPointerNull::get(t->getPointerTo()), 1); gep = builder.CreatePtrToInt(gep, getNativeWordTy()); addValueToMap(gep, inst->realOutput); break; } case fir::OpKind::Logical_Not: { iceAssert(inst->operands.size() == 1); llvm::Value* a = getOperand(inst, 0); llvm::Value* ret = builder.CreateICmpEQ(a, llvm::Constant::getNullValue(a->getType())); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Value_InsertValue: { iceAssert(inst->operands.size() >= 3); llvm::Value* str = getOperand(inst, 0); llvm::Value* elm = getOperand(inst, 1); std::vector inds; for(size_t i = 2; i < inst->operands.size(); i++) { fir::ConstantInt* ci = dcast(fir::ConstantInt, inst->operands[i]); iceAssert(ci); inds.push_back(static_cast(ci->getUnsignedValue())); } iceAssert(str->getType()->isStructTy() || str->getType()->isArrayTy()); if(str->getType()->isStructTy()) { iceAssert(elm->getType() == llvm::cast(str->getType())->getElementType(inds[0])); } else if(str->getType()->isArrayTy()) { iceAssert(elm->getType() == llvm::cast(str->getType())->getElementType()); } else { iceAssert(0); } llvm::Value* ret = builder.CreateInsertValue(str, elm, inds); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Value_ExtractValue: { iceAssert(inst->operands.size() >= 2); llvm::Value* str = getOperand(inst, 0); std::vector inds; for(size_t i = 1; i < inst->operands.size(); i++) { fir::ConstantInt* ci = dcast(fir::ConstantInt, inst->operands[i]); iceAssert(ci); inds.push_back(static_cast(ci->getUnsignedValue())); } iceAssert(str->getType()->isStructTy() || str->getType()->isArrayTy()); llvm::Value* ret = builder.CreateExtractValue(str, inds); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::SAA_GetData: case fir::OpKind::SAA_GetLength: case fir::OpKind::SAA_GetCapacity: case fir::OpKind::SAA_GetRefCountPtr: { iceAssert(inst->operands.size() == 1); llvm::Value* a = getOperand(inst, 0); iceAssert(a->getType()->isStructTy()); int ind = 0; if(inst->opKind == fir::OpKind::SAA_GetData) ind = SAA_DATA_INDEX; else if(inst->opKind == fir::OpKind::SAA_GetLength) ind = SAA_LENGTH_INDEX; else if(inst->opKind == fir::OpKind::SAA_GetCapacity) ind = SAA_CAPACITY_INDEX; else if(inst->opKind == fir::OpKind::SAA_GetRefCountPtr) ind = SAA_REFCOUNTPTR_INDEX; else iceAssert(0 && "invalid"); llvm::Value* ret = builder.CreateExtractValue(a, ind); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::SAA_SetData: case fir::OpKind::SAA_SetLength: case fir::OpKind::SAA_SetCapacity: case fir::OpKind::SAA_SetRefCountPtr: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); iceAssert(a->getType()->isStructTy()); int ind = 0; if(inst->opKind == fir::OpKind::SAA_SetData) ind = SAA_DATA_INDEX; else if(inst->opKind == fir::OpKind::SAA_SetLength) ind = SAA_LENGTH_INDEX; else if(inst->opKind == fir::OpKind::SAA_SetCapacity) ind = SAA_CAPACITY_INDEX; else if(inst->opKind == fir::OpKind::SAA_SetRefCountPtr) ind = SAA_REFCOUNTPTR_INDEX; else iceAssert(0 && "invalid"); llvm::Value* ret = builder.CreateInsertValue(a, b, ind); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::ArraySlice_GetData: case fir::OpKind::ArraySlice_GetLength: { iceAssert(inst->operands.size() == 1); llvm::Value* a = getOperand(inst, 0); iceAssert(a->getType()->isStructTy()); int ind = 0; if(inst->opKind == fir::OpKind::ArraySlice_GetData) ind = SLICE_DATA_INDEX; else if(inst->opKind == fir::OpKind::ArraySlice_GetLength) ind = SLICE_LENGTH_INDEX; else iceAssert(0 && "invalid"); llvm::Value* ret = builder.CreateExtractValue(a, ind); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::ArraySlice_SetData: case fir::OpKind::ArraySlice_SetLength: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); iceAssert(a->getType()->isStructTy()); int ind = 0; if(inst->opKind == fir::OpKind::ArraySlice_SetData) ind = SLICE_DATA_INDEX; else if(inst->opKind == fir::OpKind::ArraySlice_SetLength) ind = SLICE_LENGTH_INDEX; else iceAssert(0 && "invalid"); llvm::Value* ret = builder.CreateInsertValue(a, b, ind); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Any_GetData: case fir::OpKind::Any_GetTypeID: case fir::OpKind::Any_GetRefCountPtr: { iceAssert(inst->operands.size() == 1); llvm::Value* a = getOperand(inst, 0); iceAssert(a->getType()->isStructTy()); int ind = 0; if(inst->opKind == fir::OpKind::Any_GetTypeID) ind = ANY_TYPEID_INDEX; else if(inst->opKind == fir::OpKind::Any_GetRefCountPtr) ind = ANY_REFCOUNTPTR_INDEX; else if(inst->opKind == fir::OpKind::Any_GetData) ind = ANY_DATA_ARRAY_INDEX; else iceAssert(0 && "invalid"); llvm::Value* ret = builder.CreateExtractValue(a, ind); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Any_SetData: case fir::OpKind::Any_SetTypeID: case fir::OpKind::Any_SetRefCountPtr: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); iceAssert(a->getType()->isStructTy()); int ind = 0; if(inst->opKind == fir::OpKind::Any_SetTypeID) ind = ANY_TYPEID_INDEX; else if(inst->opKind == fir::OpKind::Any_SetRefCountPtr) ind = ANY_REFCOUNTPTR_INDEX; else if(inst->opKind == fir::OpKind::Any_SetData) ind = ANY_DATA_ARRAY_INDEX; else iceAssert(0 && "invalid"); llvm::Value* ret = builder.CreateInsertValue(a, b, ind); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Range_GetLower: case fir::OpKind::Range_GetUpper: case fir::OpKind::Range_GetStep: { unsigned int pos = 0; if(inst->opKind == fir::OpKind::Range_GetUpper) pos = 1; else if(inst->opKind == fir::OpKind::Range_GetStep) pos = 2; llvm::Value* a = getOperand(inst, 0); iceAssert(a->getType()->isStructTy()); llvm::Value* val = builder.CreateExtractValue(a, { pos }); addValueToMap(val, inst->realOutput); break; } case fir::OpKind::Range_SetLower: case fir::OpKind::Range_SetUpper: case fir::OpKind::Range_SetStep: { unsigned int pos = 0; if(inst->opKind == fir::OpKind::Range_SetUpper) pos = 1; else if(inst->opKind == fir::OpKind::Range_SetStep) pos = 2; llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); iceAssert(a->getType()->isStructTy()); iceAssert(b->getType()->isIntegerTy()); llvm::Value* ret = builder.CreateInsertValue(a, b, { pos }); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Enum_GetIndex: case fir::OpKind::Enum_GetValue: { unsigned int pos = 0; if(inst->opKind == fir::OpKind::Enum_GetValue) pos = 1; llvm::Value* a = getOperand(inst, 0); iceAssert(a->getType()->isStructTy()); llvm::Value* val = builder.CreateExtractValue(a, { pos }); addValueToMap(val, inst->realOutput); break; } case fir::OpKind::Enum_SetIndex: case fir::OpKind::Enum_SetValue: { unsigned int pos = 0; if(inst->opKind == fir::OpKind::Enum_SetValue) pos = 1; llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); iceAssert(a->getType()->isStructTy()); if(pos == 0) iceAssert(b->getType()->isIntegerTy()); llvm::Value* ret = builder.CreateInsertValue(a, b, { pos }); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Value_Select: { llvm::Value* cond = getOperand(inst, 0); llvm::Value* one = getOperand(inst, 1); llvm::Value* two = getOperand(inst, 2); iceAssert(cond->getType()->isIntegerTy() && cond->getType()->getIntegerBitWidth() == 1); iceAssert(one->getType() == two->getType()); llvm::Value* ret = builder.CreateSelect(cond, one, two); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Value_StackAlloc: case fir::OpKind::Value_CreateLVal: { iceAssert(inst->operands.size() == 1); fir::Type* ft = inst->operands[0]->getType(); llvm::Type* t = typeToLlvm(ft, module); llvm::Value* ret = builder.CreateAlloca(t); builder.CreateStore(llvm::Constant::getNullValue(t), ret); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Value_Store: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getUndecayedOperand(inst, 1); if(a->getType() != b->getType()->getPointerElementType()) error("llvm: cannot store '%s' into '%s'", inst->operands[0]->getType(), inst->operands[1]->getType()); llvm::Value* ret = builder.CreateStore(a, b); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Value_AddressOf: { iceAssert(inst->operands.size() == 1); llvm::Value* a = getUndecayedOperand(inst, 0); addValueToMap(a, inst->realOutput); break; } case fir::OpKind::Value_Dereference: { iceAssert(inst->operands.size() == 1); llvm::Value* a = getOperand(inst, 0); addValueToMap(a, inst->realOutput); break; } case fir::OpKind::RawUnion_GEP: { iceAssert(inst->operands.size() == 2); llvm::Value* a = getUndecayedOperand(inst, 0); llvm::Type* target = typeToLlvm(inst->operands[1]->getType(), module); iceAssert(a->getType()->isPointerTy() && a->getType()->getPointerElementType()->isStructTy()); auto ptr = builder.CreateConstGEP2_32(a->getType()->getPointerElementType(), a, 0, 0); ptr = builder.CreatePointerCast(ptr, target->getPointerTo()); addValueToMap(ptr, inst->realOutput); break; } case fir::OpKind::Value_GetPointerToStructMember: { // equivalent to llvm's GEP(ptr*, ptrIndex, memberIndex) error("llvm: enotsup"); } case fir::OpKind::Value_GetStructMember: { // equivalent to GEP(ptr*, 0, memberIndex) iceAssert(inst->operands.size() == 2); llvm::Value* ptr = getUndecayedOperand(inst, 0); fir::ConstantInt* ci = dcast(fir::ConstantInt, inst->operands[1]); iceAssert(ci); llvm::Value* ret = builder.CreateStructGEP(ptr->getType()->getPointerElementType(), ptr, static_cast(ci->getUnsignedValue())); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Union_GetVariantID: { // fairly straightforward. iceAssert(inst->operands.size() == 1); iceAssert(inst->operands[0]->getType()->isUnionType()); llvm::Value* uv = getOperand(inst, 0); llvm::Value* ret = builder.CreateExtractValue(uv, { 0 }); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Union_SetVariantID: { iceAssert(inst->operands.size() == 2); iceAssert(inst->operands[0]->getType()->isUnionType()); llvm::Value* uv = getOperand(inst, 0); llvm::Value* ret = builder.CreateInsertValue(uv, getOperand(inst, 1), { 0 }); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Union_GetValue: { iceAssert(inst->operands.size() == 2); iceAssert(inst->operands[0]->getType()->isUnionType()); auto ut = inst->operands[0]->getType()->toUnionType(); auto vid = dcast(fir::ConstantInt, inst->operands[1])->getSignedValue(); iceAssert(static_cast(vid) < ut->getVariantCount()); auto vt = ut->getVariant(vid)->getInteriorType(); auto lut = typeToLlvm(ut, module); auto lvt = typeToLlvm(vt, module); llvm::Value* unionVal = getOperand(inst, 0); llvm::Value* arrp = builder.CreateAlloca(lut->getStructElementType(1)); builder.CreateStore(builder.CreateExtractValue(unionVal, { 1 }), arrp); // cast to the appropriate type. llvm::Value* ret = builder.CreatePointerCast(arrp, lvt->getPointerTo()); ret = builder.CreateLoad(ret); addValueToMap(ret, inst->realOutput); break; } case fir::OpKind::Union_SetValue: { iceAssert(inst->operands.size() == 3); iceAssert(inst->operands[0]->getType()->isUnionType()); auto luv = getOperand(inst, 0); auto lut = luv->getType(); auto val = getOperand(inst, 2); // this is not really efficient, but without a significant // re-architecting of how we handle structs and pointers and shit // (to let us use GEP for everything), this will have to do. llvm::Value* arrp = builder.CreateAlloca(lut->getStructElementType(1)); // cast to the correct pointer type auto valp = builder.CreateBitCast(arrp, val->getType()->getPointerTo()); builder.CreateStore(val, valp); // cast it back, then load it. arrp = builder.CreateBitCast(valp, arrp->getType()); auto arr = builder.CreateLoad(arrp); // insert it back into the union. luv = builder.CreateInsertValue(luv, arr, { 1 }); // then insert the id. luv = builder.CreateInsertValue(luv, getOperand(inst, 1), { 0 }); addValueToMap(luv, inst->realOutput); break; } case fir::OpKind::Unreachable: { builder.CreateUnreachable(); break; } case fir::OpKind::Invalid: { // note we don't use "default" to catch // new opkinds that we forget to add. iceAssert("invalid opcode" && 0); } } } } } return module; } } ================================================ FILE: source/backend/x64AsmBackend.cpp ================================================ // x64AsmBackend.cpp // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #include "backend.h" namespace backend { x64Backend::x64Backend(CompiledData& dat, const std::vector& inputs, const std::string& output) : Backend(0, dat, inputs, output) { } void x64Backend::performCompilation() { _error_and_exit("enotsup\n"); } void x64Backend::optimiseProgram() { _error_and_exit("enotsup\n"); } void x64Backend::writeOutput() { _error_and_exit("enotsup\n"); } std::string x64Backend::str() { return "x64 Assembly"; } } ================================================ FILE: source/codegen/alloc.cpp ================================================ // alloc.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "sst.h" #include "codegen.h" #include "platform.h" #include "gluecode.h" static fir::Function* getCheckNegativeLengthFunction(cgn::CodegenState* cs) { auto fname = fir::Name::obfuscate("alloc_checkneg"); fir::Function* checkf = cs->module->getFunction(fname); if(!checkf) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ fir::Type::getNativeWord(), fir::Type::getCharSlice(false) }, fir::Type::getVoid()), fir::LinkageType::Internal); func->setAlwaysInline(); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); fir::Value* s1 = func->getArguments()[0]; fir::Value* s2 = func->getArguments()[1]; fir::IRBlock* failb = cs->irb.addNewBlockInFunction("fail", func); fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", func); // make the thing auto isNeg = cs->irb.ICmpLT(s1, fir::ConstantInt::getNative(0)); cs->irb.CondBranch(isNeg, failb, merge); cs->irb.setCurrentBlock(failb); { cgn::glue::printRuntimeError(cs, s2, "tried to allocate a negative ('%ld') amount of memory\n", { s1 }); } cs->irb.setCurrentBlock(merge); cs->irb.ReturnVoid(); cs->irb.setCurrentBlock(restore); checkf = func; } iceAssert(checkf); return checkf; } static fir::Value* performAllocation(cgn::CodegenState* cs, sst::AllocOp* alloc, fir::Type* type, std::vector counts, bool isRaw) { auto callSetFunction = [cs](fir::Type* type, sst::AllocOp* alloc, fir::Value* ptr, fir::Value* count) -> void { auto callUserCode = [cs, alloc](fir::Value* elmp, fir::Value* idxp) { iceAssert(alloc->initBlockIdx); iceAssert(alloc->initBlockVar); // ok, then. create the variables: cs->addVariableUsingStorage(alloc->initBlockIdx, idxp); cs->addVariableUsingStorage(alloc->initBlockVar, elmp); alloc->initBlock->codegen(cs); }; auto arrp = ptr; auto ctrp = cs->irb.CreateLValue(fir::Type::getNativeWord()); auto actuallyStore = [cs, type, alloc](fir::Value* ptr) -> void { if(type->isClassType()) { auto constr = dcast(sst::FunctionDefn, alloc->constructor); iceAssert(constr); //! here, the arguments are called once per element. auto value = cs->constructClassWithArguments(type->toClassType(), constr, alloc->arguments); cs->autoAssignRefCountedValue(cs->irb.Dereference(ptr), value, true); } else if(type->isStructType()) { auto value = cs->getConstructedStructValue(type->toStructType(), alloc->arguments); cs->autoAssignRefCountedValue(cs->irb.Dereference(ptr), value, true); } else { auto value = cs->getDefaultValue(type); cs->autoAssignRefCountedValue(cs->irb.Dereference(ptr), value, true); } }; if(alloc->counts.empty()) { actuallyStore(arrp); } else { cs->createWhileLoop([cs, ctrp, count](auto pass, auto fail) { auto cond = cs->irb.ICmpLT(ctrp, count); cs->irb.CondBranch(cond, pass, fail); }, [cs, callUserCode, actuallyStore, alloc, ctrp, arrp]() { auto ptr = cs->irb.GetPointer(arrp, ctrp); actuallyStore(ptr); if(alloc->initBlock) callUserCode(cs->irb.Dereference(ptr), ctrp); cs->irb.Store(cs->irb.Add(ctrp, fir::ConstantInt::getNative(1)), ctrp); }); } }; if(counts.empty() || isRaw) { fir::Value* cnt = (counts.empty() ? fir::ConstantInt::getNative(1) : cs->oneWayAutocast(counts[0]->codegen(cs, fir::Type::getNativeWord()).value, fir::Type::getNativeWord())); //* if we don't have a count, then we just return a T* -- no arrays, nothing. auto sz = cs->irb.Multiply(cs->irb.Sizeof(type), cnt); auto mem = cs->irb.Call(cgn::glue::misc::getMallocWrapperFunction(cs), sz, fir::ConstantCharSlice::get(alloc->loc.shortString())); mem = cs->irb.PointerTypeCast(mem, type->getMutablePointerTo()); callSetFunction(type, alloc, mem, cnt); // check if we were supposed to be immutable if(!alloc->isMutable) mem = cs->irb.PointerTypeCast(mem, mem->getType()->getImmutablePointerVersion()); return mem; } else { auto ecount = counts[0]; auto count = cs->oneWayAutocast(ecount->codegen(cs, fir::Type::getNativeWord()).value, fir::Type::getNativeWord()); if(!count || !count->getType()->isIntegerType()) error(ecount, "expected integer type for length, found '%s' instead", (count ? count->getType()->str() : "null")); // make sure the length isn't negative auto checkf = getCheckNegativeLengthFunction(cs); iceAssert(checkf); cs->irb.Call(checkf, count, fir::ConstantCharSlice::get(ecount->loc.toString())); auto arr = cs->irb.CreateValue(fir::DynamicArrayType::get(type)); auto expandfn = cgn::glue::saa_common::generateReserveAtLeastFunction(cs, arr->getType()); iceAssert(expandfn); arr = cs->irb.Call(expandfn, arr, count); arr = cs->irb.SetSAALength(arr, count); callSetFunction(type, alloc, cs->irb.GetSAAData(arr), count); cs->addRefCountedValue(arr); return arr; } } CGResult sst::AllocOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); if(this->counts.size() > 1) error(this, "multi-dimensional arrays are not supported yet."); return CGResult(performAllocation(cs, this, this->elmType, this->counts, this->attrs.has(attr::RAW))); } CGResult sst::DeallocOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); auto freef = cs->getOrDeclareLibCFunction(FREE_MEMORY_FUNC); iceAssert(freef); auto value = this->expr->codegen(cs).value; auto ty = value->getType(); iceAssert(ty->isPointerType()); fir::Value* ptr = cs->irb.PointerTypeCast(value, fir::Type::getMutInt8Ptr()); cs->irb.Call(freef, ptr); return CGResult(0); } ================================================ FILE: source/codegen/arithmetic.cpp ================================================ // arithmetic.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "sst.h" #include "codegen.h" #include "gluecode.h" #include "typecheck.h" namespace sst { CGResult BinaryOp::_codegen(cgn::CodegenState* cs, fir::Type* inferred) { iceAssert(!Operator::isAssignment(this->op)); if(this->op == Operator::TypeCast) { auto target = this->right->codegen(cs).value->getType(); auto value = this->left->codegen(cs).value; auto vt = value->getType(); if(vt->isConstantNumberType() && (target->isFloatingPointType() || target->isIntegerType())) { auto cn = dcast(fir::ConstantNumber, value); if(!cn) error(this->left, "what"); return CGResult(cs->unwrapConstantNumber(cn, target)); } else if(vt->isEnumType()) { auto res = cs->irb.AppropriateCast(cs->irb.GetEnumCaseValue(value), target); if(!res) { error(this, "case type of '%s' is '%s', cannot cast to type '%s'", vt, vt->toEnumType()->getCaseType(), target); } return CGResult(res); } else if(vt->isAnyType()) { auto fn = cgn::glue::any::generateGetValueFromAnyFunction(cs, target); iceAssert(fn); return CGResult(cs->irb.Call(fn, value)); } else if(vt->isUnionType() && target->isUnionVariantType()) { if(auto parent = target->toUnionVariantType()->getParentUnion(); parent != vt) { error(this, "unwrapping union of type '%s' to variant ('%s') of unrelated union '%s'", vt, target->toUnionVariantType()->getName(), parent); } else { fir::IRBlock* invalid = cs->irb.addNewBlockInFunction("invalid", cs->irb.getCurrentFunction()); fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", cs->irb.getCurrentFunction()); auto targetId = fir::ConstantInt::getNative(target->toUnionVariantType()->getVariantId()); auto variantId = cs->irb.GetUnionVariantID(value); auto valid = cs->irb.ICmpEQ(targetId, variantId); cs->irb.CondBranch(valid, merge, invalid); cs->irb.setCurrentBlock(invalid); { // TODO: actually say what the variant was -- requires creating a runtime array of the names of the variants, // TODO: probably. might be easier once we have type info at runtime! cgn::glue::printRuntimeError(cs, fir::ConstantCharSlice::get(cs->loc().toString()), "invalid unwrap of value of union '%s' into variant '%s'", { cs->module->createGlobalString(vt->str()), cs->module->createGlobalString(target->toUnionVariantType()->getName()) } ); } cs->irb.setCurrentBlock(merge); return CGResult(cs->irb.GetUnionVariantData(value, target->toUnionVariantType()->getVariantId())); } } else { auto res = cs->irb.AppropriateCast(value, target); if(!res) { error(this, "no appropriate cast from type '%s' to '%s'", vt, target); } return CGResult(res); } } else if(this->op == Operator::TypeIs) { auto value = this->left->codegen(cs).value; auto target = this->right->codegen(cs).value->getType(); if(value->getType()->isAnyType()) { // get the type out. auto res = cs->irb.BitwiseAND(cs->irb.GetAnyTypeID(value), cs->irb.BitwiseNOT(fir::ConstantInt::getUNative(BUILTIN_ANY_FLAG_MASK))); return CGResult(res = cs->irb.ICmpEQ(res, fir::ConstantInt::getUNative(target->getID()))); } else if(value->getType()->isUnionType() && target->isUnionVariantType()) { // it's slightly more complicated. auto vid1 = cs->irb.GetUnionVariantID(value); auto vid2 = fir::ConstantInt::getNative(target->toUnionVariantType()->getVariantId()); return CGResult(cs->irb.ICmpEQ(vid1, vid2)); } else { auto res = fir::ConstantInt::getUNative(value->getType()->getID()); return CGResult(cs->irb.ICmpEQ(res, fir::ConstantInt::getUNative(target->getID()))); } } if(this->op == Operator::LogicalAnd || this->op == Operator::LogicalOr) return cs->performLogicalBinaryOperation(this); // TODO: figure out a better way auto _lr = this->left->codegen(cs/*, inferred*/); auto _rr = this->right->codegen(cs/*, inferred*/); auto [ l, r ] = std::make_tuple(_lr.value, _rr.value); // auto [ lt, rt ] = std::make_tuple(l.value->getType(), r.value->getType()); if(this->overloadedOpFunction) { // fantastic, just call this piece of shit. auto func = dcast(fir::Function, this->overloadedOpFunction->codegen(cs, 0).value); iceAssert(func); iceAssert(func->getArgumentCount() == 2); fir::Value* lv = cs->oneWayAutocast(l, func->getArguments()[0]->getType()); fir::Value* rv = cs->oneWayAutocast(r, func->getArguments()[0]->getType()); if(lv->getType() != func->getArguments()[0]->getType()) { SpanError::make(SimpleError::make(this->left->loc, "mismatched types for left side of overloaded binary operator '%s'; expected '%s', found '%s' instead", this->op, func->getArguments()[0]->getType(), lv->getType()) )->append(SimpleError::make(MsgType::Note, this->overloadedOpFunction->loc, "operator was overloaded here:")) ->postAndQuit(); } else if(rv->getType() != func->getArguments()[1]->getType()) { SpanError::make(SimpleError::make(this->right->loc, "mismatched types for right side of overloaded binary operator '%s'; expected '%s', found '%s' instead", this->op, func->getArguments()[1]->getType(), rv->getType()) )->append(SimpleError::make(MsgType::Note, this->overloadedOpFunction->loc, "operator was overloaded here:")) ->postAndQuit(); } // ok, call that guy. return CGResult(cs->irb.Call(func, lv, rv)); } else { return cs->performBinaryOperation(this->loc, { this->left->loc, l }, { this->right->loc, r }, this->op); } } CGResult UnaryOp::_codegen(cgn::CodegenState* cs, fir::Type* inferred) { auto val = this->expr->codegen(cs, inferred).value; auto ty = val->getType(); if(this->overloadedOpFunction) { // fantastic, just call this piece of shit. auto func = dcast(fir::Function, this->overloadedOpFunction->codegen(cs, 0).value); iceAssert(func); iceAssert(func->getArgumentCount() == 1); val = cs->oneWayAutocast(val, func->getArguments()[0]->getType()); if(val->getType() != func->getArguments()[0]->getType()) { SpanError::make(SimpleError::make(this->expr->loc, "mismatched types for overloaded unary operator '%s'; " "expected '%s', found '%s' instead", this->op, func->getArguments()[0]->getType(), val->getType())) ->append(SimpleError::make(MsgType::Note, this->overloadedOpFunction->loc, "operator was overloaded here:")) ->postAndQuit(); } // ok, call that guy. return CGResult(cs->irb.Call(func, val)); } if(this->op == Operator::LogicalNot) { iceAssert(ty->isBoolType()); if(auto c = dcast(fir::ConstantInt, val)) { bool b = c->getSignedValue(); return CGResult(fir::ConstantBool::get(!b)); } else { return CGResult(cs->irb.LogicalNot(val)); } } else if(this->op == Operator::UnaryPlus) { return CGResult(val); } else if(this->op == Operator::UnaryMinus) { if(auto ci = dcast(fir::ConstantInt, val)) { iceAssert(ci->getType()->isSignedIntType()); return CGResult(fir::ConstantInt::get(ci->getType(), -1 * ci->getSignedValue())); } else if(auto cf = dcast(fir::ConstantFP, val)) { return CGResult(fir::ConstantFP::get(cf->getType(), -1 * cf->getValue())); } else { return CGResult(cs->irb.Negate(val)); } } else if(this->op == Operator::PointerDeref) { iceAssert(ty->isPointerType()); return CGResult(cs->irb.Dereference(val)); } else if(this->op == Operator::AddressOf) { if(!val->islvalue()) error(this, "cannot take address of a non-lvalue"); else if(val->getType()->isFunctionType()) error(this, "cannot take the address of a function; use it as a value type"); return CGResult(cs->irb.AddressOf(val, false)); } else if(this->op == Operator::BitwiseNot) { iceAssert(ty->isIntegerType() && !ty->isSignedIntType()); if(auto ci = dcast(fir::ConstantInt, val)) { return CGResult(fir::ConstantInt::get(ci->getType(), ~(ci->getUnsignedValue()))); } else { return CGResult(cs->irb.BitwiseNOT(val)); } } error(this, "not a unary op"); } } namespace cgn { CGResult CodegenState::performBinaryOperation(const Location& loc, std::pair lhs, std::pair rhs, std::string op) { auto unsupportedError = [loc, op](const Location& al, fir::Type* a, const Location& bl, fir::Type* b) { SpanError::make(SimpleError::make(loc, "unsupported operator '%s' between types '%s' and '%s'", op, a, b)) ->add(util::ESpan(al, strprintf("type '%s'", a))) ->add(util::ESpan(bl, strprintf("type '%s'", b))) ->postAndQuit(); }; auto l = lhs.second; auto r = rhs.second; auto lt = l->getType(); auto rt = r->getType(); auto lv = l; auto rv = r; if(Operator::isComparison(op)) { auto [ lr, rr ] = this->autoCastValueTypes(l, r); if(!lr || !rr) unsupportedError(lhs.first, lt, rhs.first, rt); iceAssert(lr && rr); auto [ lt, rt ] = std::make_pair(lr->getType(), rr->getType()); // do comparison if((lt->isIntegerType() && rt->isIntegerType()) || (lt->isPointerType() && rt->isPointerType())) { // we should cast these to be similar-ish. if(op == Operator::CompareEQ) return CGResult(this->irb.ICmpEQ(lr, rr)); if(op == Operator::CompareNEQ) return CGResult(this->irb.ICmpNEQ(lr, rr)); if(op == Operator::CompareLT) return CGResult(this->irb.ICmpLT(lr, rr)); if(op == Operator::CompareLEQ) return CGResult(this->irb.ICmpLEQ(lr, rr)); if(op == Operator::CompareGT) return CGResult(this->irb.ICmpGT(lr, rr)); if(op == Operator::CompareGEQ) return CGResult(this->irb.ICmpGEQ(lr, rr)); error("no"); } else if(lt->isFloatingPointType() && rt->isFloatingPointType()) { if(op == Operator::CompareEQ) return CGResult(this->irb.FCmpEQ_ORD(lr, rr)); if(op == Operator::CompareNEQ) return CGResult(this->irb.FCmpNEQ_ORD(lr, rr)); if(op == Operator::CompareLT) return CGResult(this->irb.FCmpLT_ORD(lr, rr)); if(op == Operator::CompareLEQ) return CGResult(this->irb.FCmpLEQ_ORD(lr, rr)); if(op == Operator::CompareGT) return CGResult(this->irb.FCmpGT_ORD(lr, rr)); if(op == Operator::CompareGEQ) return CGResult(this->irb.FCmpGEQ_ORD(lr, rr)); error("no"); } else if((lt->isPrimitiveType() && rt->isConstantNumberType()) || (lt->isConstantNumberType() && rt->isPrimitiveType())) { if(lr->getType()->isFloatingPointType()) { if(op == Operator::CompareEQ) return CGResult(this->irb.FCmpEQ_ORD(lr, rr)); if(op == Operator::CompareNEQ) return CGResult(this->irb.FCmpNEQ_ORD(lr, rr)); if(op == Operator::CompareLT) return CGResult(this->irb.FCmpLT_ORD(lr, rr)); if(op == Operator::CompareLEQ) return CGResult(this->irb.FCmpLEQ_ORD(lr, rr)); if(op == Operator::CompareGT) return CGResult(this->irb.FCmpGT_ORD(lr, rr)); if(op == Operator::CompareGEQ) return CGResult(this->irb.FCmpGEQ_ORD(lr, rr)); error("no"); } else { if(op == Operator::CompareEQ) return CGResult(this->irb.ICmpEQ(lr, rr)); if(op == Operator::CompareNEQ) return CGResult(this->irb.ICmpNEQ(lr, rr)); if(op == Operator::CompareLT) return CGResult(this->irb.ICmpLT(lr, rr)); if(op == Operator::CompareLEQ) return CGResult(this->irb.ICmpLEQ(lr, rr)); if(op == Operator::CompareGT) return CGResult(this->irb.ICmpGT(lr, rr)); if(op == Operator::CompareGEQ) return CGResult(this->irb.ICmpGEQ(lr, rr)); error("no"); } } else if(lt->isStringType() && rt->isStringType()) { auto cmpfn = cgn::glue::string::getCompareFunction(this); fir::Value* res = this->irb.Call(cmpfn, lv, rv); fir::Value* zero = fir::ConstantInt::getNative(0); if(op == Operator::CompareEQ) return CGResult(this->irb.ICmpEQ(res, zero)); if(op == Operator::CompareNEQ) return CGResult(this->irb.ICmpNEQ(res, zero)); if(op == Operator::CompareLT) return CGResult(this->irb.ICmpLT(res, zero)); if(op == Operator::CompareLEQ) return CGResult(this->irb.ICmpLEQ(res, zero)); if(op == Operator::CompareGT) return CGResult(this->irb.ICmpGT(res, zero)); if(op == Operator::CompareGEQ) return CGResult(this->irb.ICmpGEQ(res, zero)); error("no"); } else if(lt->isEnumType() && lt == rt) { auto li = this->irb.GetEnumCaseIndex(lv); auto ri = this->irb.GetEnumCaseIndex(rv); if(op == Operator::CompareEQ) return CGResult(this->irb.ICmpEQ(li, ri)); if(op == Operator::CompareNEQ) return CGResult(this->irb.ICmpNEQ(li, ri)); if(op == Operator::CompareLT) return CGResult(this->irb.ICmpLT(li, ri)); if(op == Operator::CompareLEQ) return CGResult(this->irb.ICmpLEQ(li, ri)); if(op == Operator::CompareGT) return CGResult(this->irb.ICmpGT(li, ri)); if(op == Operator::CompareGEQ) return CGResult(this->irb.ICmpGEQ(li, ri)); error("no"); } else if((lt->isDynamicArrayType() || lt->isArraySliceType()) && lt == rt) { //! use opf when we have operator overloads auto cmpfn = cgn::glue::array::getCompareFunction(this, lt, 0); fir::Value* res = this->irb.Call(cmpfn, lv, rv); fir::Value* zero = fir::ConstantInt::getNative(0); if(op == Operator::CompareEQ) return CGResult(this->irb.ICmpEQ(res, zero)); if(op == Operator::CompareNEQ) return CGResult(this->irb.ICmpNEQ(res, zero)); if(op == Operator::CompareLT) return CGResult(this->irb.ICmpLT(res, zero)); if(op == Operator::CompareLEQ) return CGResult(this->irb.ICmpLEQ(res, zero)); if(op == Operator::CompareGT) return CGResult(this->irb.ICmpGT(res, zero)); if(op == Operator::CompareGEQ) return CGResult(this->irb.ICmpGEQ(res, zero)); error("no"); } else { error("unsupported comparison between types '%s' and '%s'", lt, rt); } } else { if((lt->isPrimitiveType() || lt->isConstantNumberType()) && (rt->isPrimitiveType() || rt->isConstantNumberType())) { auto [ lr, rr ] = this->autoCastValueTypes(l, r); return CGResult(this->irb.BinaryOp(op, lr, rr)); } else if((lt->isPointerType() && (rt->isIntegerType() || rt->isConstantNumberType())) || ((lt->isIntegerType() || lt->isConstantNumberType()) && rt->isPointerType())) { auto ofsv = (lt->isPointerType() ? rv : lv); auto ofs = this->oneWayAutocast(ofsv, fir::Type::getNativeWord()); iceAssert(ofs->getType()->isIntegerType()); auto ptr = (lt->isPointerType() ? lv : rv); ptr = this->irb.GetPointer(ptr, ofs); return CGResult(ptr); } else if(lt->isStringType() && rt->isStringType()) { if(op != Operator::Plus) unsupportedError(lhs.first, lt, rhs.first, rt); #if 0 // ok. // if we're both string literals, then fuck it, do it compile-time if(dcast(fir::ConstantCharSlice, lv) && dcast(fir::ConstantCharSlice, rv)) { std::string cls = dcast(fir::ConstantCharSlice, lv)->getValue(); std::string crs = dcast(fir::ConstantCharSlice, rv)->getValue(); info(loc, "const strings"); return CGResult(fir::ConstantCharSlice::get(cls + crs)); } #endif auto appfn = cgn::glue::string::getConstructFromTwoFunction(this); auto res = this->irb.Call(appfn, this->irb.CreateSliceFromSAA(lv, false), this->irb.CreateSliceFromSAA(rv, false)); this->addRefCountedValue(res); return CGResult(res); } else if((lt->isStringType() && rt->isCharSliceType()) || (lt->isCharSliceType() && rt->isStringType())) { if(op != Operator::Plus) unsupportedError(lhs.first, lt, rhs.first, rt); // make life easier if(lt->isCharSliceType()) { std::swap(lt, rt); std::swap(lv, rv); } auto appfn = cgn::glue::string::getConstructFromTwoFunction(this); auto res = this->irb.Call(appfn, this->irb.CreateSliceFromSAA(lv, false), rv); this->addRefCountedValue(res); return CGResult(res); } else if((lt->isStringType() && rt->isCharType()) || (lt->isCharType() && rt->isStringType())) { if(op != Operator::Plus) unsupportedError(lhs.first, lt, rhs.first, rt); // make life easier if(lt->isCharType()) { std::swap(lt, rt); std::swap(lv, rv); } #if 0 if(dcast(fir::ConstantCharSlice, lv) && dcast(fir::ConstantChar, rv)) { std::string cls = dcast(fir::ConstantCharSlice, lv)->getValue(); char crs = dcast(fir::ConstantChar, rv)->getValue(); info(loc, "const strings"); return CGResult(fir::ConstantCharSlice::get(cls + crs)); } #endif auto appfn = cgn::glue::string::getConstructWithCharFunction(this); auto res = this->irb.Call(appfn, this->irb.CreateSliceFromSAA(lv, true), rv); this->addRefCountedValue(res); return CGResult(res); } else if(lt->isDynamicArrayType() && rt->isDynamicArrayType() && lt->getArrayElementType() == rt->getArrayElementType()) { // check what we're doing if(op != Operator::Plus) unsupportedError(lhs.first, lt, rhs.first, rt); // ok, do the append auto maketwof = cgn::glue::array::getConstructFromTwoFunction(this, lt->toDynamicArrayType()); fir::Value* res = this->irb.Call(maketwof, this->irb.CreateSliceFromSAA(lv, false), this->irb.CreateSliceFromSAA(rv, false)); this->addRefCountedValue(res); return CGResult(res); // error(loc, "i'm gonna stop you right here"); } else { unsupportedError(lhs.first, lt, rhs.first, rt); doTheExit(); } } } } ================================================ FILE: source/codegen/assign.cpp ================================================ // assign.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "sst.h" #include "codegen.h" #include "gluecode.h" sst::AssignOp::AssignOp(const Location& l) : Expr(l, fir::Type::getVoid()) { this->readableName = "assignment statement"; } sst::TupleAssignOp::TupleAssignOp(const Location& l) : Expr(l, fir::Type::getVoid()) { this->readableName = "destructuring assignment statement"; } CGResult sst::AssignOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); auto lr = this->left->codegen(cs).value; auto lt = lr->getType(); if(!lr->islvalue()) { SpanError::make(SimpleError::make(this->loc, "cannot assign to non-lvalue (most likely a temporary) expression")) ->add(util::ESpan(this->left->loc, "here")) ->postAndQuit(); } else if(lr->isConst()) { SpanError::make(SimpleError::make(this->loc, "cannot assign to immutable expression")) ->add(util::ESpan(this->left->loc, "here")) ->postAndQuit(); } // okay, i guess auto rr = this->right->codegen(cs, lt).value; auto rt = rr->getType(); if(this->op != Operator::Assign) { // ok it's a compound assignment // auto [ newl, newr ] = cs->autoCastValueTypes(lr, rr); auto nonass = Operator::getNonAssignmentVersion(this->op); // some things -- if we're doing +=, and the types are supported, then just call the actual // append function, instead of doing the + first then assigning it. if(nonass == Operator::Plus) { if(lt->isDynamicArrayType() && lt == rt) { // right then. if(!lr->islvalue()) error(this, "cannot append to an r-value array"); auto appendf = cgn::glue::array::getAppendFunction(cs, lt->toDynamicArrayType()); //? are there any ramifications for these actions for ref-counted things? auto res = cs->irb.Call(appendf, lr, cs->irb.CreateSliceFromSAA(rr, false)); cs->irb.Store(res, lr); return CGResult(0); } else if(lt->isDynamicArrayType() && lt->getArrayElementType() == rt) { // right then. if(!lr->islvalue()) error(this, "cannot append to an r-value array"); auto appendf = cgn::glue::array::getElementAppendFunction(cs, lt->toDynamicArrayType()); //? are there any ramifications for these actions for ref-counted things? auto res = cs->irb.Call(appendf, lr, rr); cs->irb.Store(res, lr); return CGResult(0); } else if(lt->isStringType() && lt == rt) { // right then. if(!lr->islvalue()) error(this, "cannot append to an r-value array"); auto appendf = cgn::glue::string::getAppendFunction(cs); //? are there any ramifications for these actions for ref-counted things? auto res = cs->irb.Call(appendf, lr, cs->irb.CreateSliceFromSAA(rr, true)); cs->irb.Store(res, lr); return CGResult(0); } else if(lt->isStringType() && rt->isCharType()) { // right then. if(!lr->islvalue()) error(this, "cannot append to an r-value string"); auto appendf = cgn::glue::string::getCharAppendFunction(cs); //? are there any ramifications for these actions for ref-counted things? auto res = cs->irb.Call(appendf, lr, rr); cs->irb.Store(res, lr); return CGResult(0); } } // do the op first auto res = cs->performBinaryOperation(this->loc, { this->left->loc, lr }, { this->right->loc, rr }, nonass); // assign the res to the thing rr = res.value; } rr = cs->oneWayAutocast(rr, lt); if(rr == 0) error(this, "invalid assignment from value of type '%s' to expected type '%s'", rt, lt); // ok then if(lt != rr->getType()) error(this, "what? left = %s, right = %s", lt, rr->getType()); cs->autoAssignRefCountedValue(lr, rr, /* isInitial: */ false); return CGResult(0); } CGResult sst::TupleAssignOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); auto tuple = this->right->codegen(cs).value; if(!tuple->getType()->isTupleType()) error(this->right, "expected tuple type in assignment to tuple on left-hand-side; found type '%s' instead", tuple->getType()); auto tty = tuple->getType()->toTupleType(); std::vector results; size_t idx = 0; for(auto v : this->lefts) { auto res = v->codegen(cs, tty->getElementN(idx)); if(!res->islvalue()) error(v, "cannot assign to non-lvalue expression in tuple assignment"); if(res->isConst()) error(v, "cannot assign to constant in tuple assignment"); results.push_back(res); idx++; } for(size_t i = 0; i < idx; i++) { auto lr = results[i]; auto val = cs->irb.ExtractValue(tuple, { i }); auto rr = cs->oneWayAutocast(val, lr.value->getType()); if(!rr || rr->getType() != lr.value->getType()) { error(this->right, "mismatched types in assignment to tuple element %d; assigning type '%s' to '%s'", val->getType(), lr.value->getType()); } cs->autoAssignRefCountedValue(lr.value, rr, /* isInitial: */ false); } return CGResult(0); } ================================================ FILE: source/codegen/autocasting.cpp ================================================ // autocasting.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "sst.h" #include "errors.h" #include "codegen.h" #include "gluecode.h" #include "typecheck.h" namespace cgn { fir::ConstantValue* CodegenState::unwrapConstantNumber(fir::ConstantValue* cv) { iceAssert(cv->getType()->isConstantNumberType()); auto cn = dcast(fir::ConstantNumber, cv); iceAssert(cn); auto ty = cv->getType()->toConstantNumberType(); iceAssert(ty); if(ty->isFloating()) { if(ty->getMinBits() <= fir::Type::getFloat64()->getBitWidth()) return fir::ConstantFP::getFloat64(cn->getDouble()); else error("float overflow"); } else { if(ty->getMinBits() < fir::Type::getNativeWord()->getBitWidth() - 1) return fir::ConstantInt::getNative(cn->getInt64()); else if(!ty->isSigned() && ty->getMinBits() <= fir::Type::getNativeUWord()->getBitWidth()) return fir::ConstantInt::getUNative(cn->getUint64()); else error("int overflow"); } } static fir::ConstantValue* _unwrapConstantNumber(CodegenState* cs, fir::ConstantNumber* num, fir::Type* target, bool isAutocast) { if(!(target->isIntegerType() || target->isFloatingPointType())) error(cs->loc(), "unable to cast number literal to inferred type '%s'", target); auto ty = num->getType()->toConstantNumberType(); bool signConvert = false; if(ty->isFloating() && target->isIntegerType()) { if(isAutocast) return 0; warn(cs->loc(), "casting floating-point literal to integer type '%s' will cause a truncation", target); } else if(target->isIntegerType() && !target->isSignedIntType() && ty->isSigned()) { if(isAutocast) return 0; warn(cs->loc(), "casting negative literal to an unsigned integer type '%s'", target); signConvert = true; } if(target->toPrimitiveType()->getBitWidth() < ty->getMinBits()) { // TODO: actually do what we say. warn(cs->loc(), "casting literal to type '%s' will cause an overflow; value will be truncated bitwise to fit", target); } if(signConvert) { // eg. ((size_t) -1) gives SIZET_MAX, basically. // so what we do, is we get the max of the target type, // then subtract (num - 1) if(target == fir::Type::getUint8()) return fir::ConstantInt::get(target, num->getUint8()); else if(target == fir::Type::getUint16()) return fir::ConstantInt::get(target, num->getUint16()); else if(target == fir::Type::getUint32()) return fir::ConstantInt::get(target, num->getUint32()); else if(target == fir::Type::getUint64()) return fir::ConstantInt::get(target, num->getUint64()); else error("what %s", target); } if(target == fir::Type::getFloat32()) return fir::ConstantFP::getFloat32(num->getFloat()); else if(target == fir::Type::getFloat64()) return fir::ConstantFP::getFloat64(num->getDouble()); else if(target == fir::Type::getInt8()) return fir::ConstantInt::get(target, num->getInt8()); else if(target == fir::Type::getInt16()) return fir::ConstantInt::get(target, num->getInt16()); else if(target == fir::Type::getInt32()) return fir::ConstantInt::get(target, num->getInt32()); else if(target == fir::Type::getInt64()) return fir::ConstantInt::get(target, num->getInt64()); else if(target == fir::Type::getUint8()) return fir::ConstantInt::get(target, num->getUint8()); else if(target == fir::Type::getUint16()) return fir::ConstantInt::get(target, num->getUint16()); else if(target == fir::Type::getUint32()) return fir::ConstantInt::get(target, num->getUint32()); else if(target == fir::Type::getUint64()) return fir::ConstantInt::get(target, num->getUint64()); else if(target == fir::Type::getNativeWord()) return fir::ConstantInt::get(target, num->getInt64()); else if(target == fir::Type::getNativeUWord()) return fir::ConstantInt::get(target, num->getUint64()); else error("unsupported type '%s'", target); } fir::ConstantValue* CodegenState::unwrapConstantNumber(fir::ConstantNumber* cv, fir::Type* target) { if(target) return _unwrapConstantNumber(this, cv, target, false); else return this->unwrapConstantNumber(cv); } // TODO: maybe merge/refactor this and the two-way autocast into one function, // there's a bunch of duplication here fir::Value* CodegenState::oneWayAutocast(fir::Value* from, fir::Type* target) { if(!from) return 0; auto fromType = from->getType(); if(fromType == target) return from; fir::Value* result = 0; if(fromType->isNullType() && target->isPointerType()) { result = this->irb.PointerTypeCast(from, target); } else if(fromType->isIntegerType() && target->isIntegerType() && fromType->isSignedIntType() == target->isSignedIntType() && target->getBitWidth() >= fromType->getBitWidth()) { result = this->irb.IntSizeCast(from, target); } else if(fromType->isPointerType() && target->isBoolType()) { //* support implicit casting for null checks result = this->irb.ICmpNEQ(from, fir::ConstantValue::getZeroValue(fromType)); } else if(fromType->isFloatingPointType() && target->isFloatingPointType() && target->getBitWidth() >= fromType->getBitWidth()) { result = this->irb.FExtend(from, target); } else if(fromType->isCharSliceType() && target == fir::Type::getInt8Ptr()) { result = this->irb.GetArraySliceData(from); } else if(fromType->isStringType() && target == fir::Type::getInt8Ptr()) { result = this->irb.PointerTypeCast(this->irb.GetSAAData(from), fir::Type::getInt8Ptr()); } else if(fromType->isStringType() && target->isCharSliceType()) { auto ret = this->irb.CreateValue(target); ret = this->irb.SetArraySliceData(ret, this->irb.GetSAAData(from)); ret = this->irb.SetArraySliceLength(ret, this->irb.GetSAALength(from)); result = ret; } else if(fromType->isDynamicArrayType() && target->isArraySliceType() && target->getArrayElementType() == fromType->getArrayElementType()) { // ok, then auto ret = this->irb.CreateValue(fir::ArraySliceType::get(fromType->getArrayElementType(), target->toArraySliceType()->isMutable())); ret = this->irb.SetArraySliceData(ret, this->irb.GetSAAData(from)); ret = this->irb.SetArraySliceLength(ret, this->irb.GetSAALength(from)); result = ret; } else if(fromType->isPointerType() && target->isPointerType() && fromType->getPointerElementType()->isClassType() && fromType->getPointerElementType()->toClassType()->hasParent(target->getPointerElementType())) { auto ret = this->irb.PointerTypeCast(from, target); result = ret; } else if(fromType->isPointerType() && target->isPointerType() && fromType->getPointerElementType() == target->getPointerElementType() && fromType->isMutablePointer() && target->isImmutablePointer()) { auto ret = this->irb.PointerTypeCast(from, target); result = ret; } else if(fromType->isArraySliceType() && target->isVariadicArrayType() && (fromType->getArrayElementType() == target->getArrayElementType())) { //* note: we can cheat, since at the llvm level there's no mutability distinction. auto ret = this->irb.Bitcast(from, target); result = ret; } else if(fromType->isArraySliceType() && target->isArraySliceType() && (fromType->getArrayElementType() == target->getArrayElementType()) && fromType->toArraySliceType()->isMutable() && !target->toArraySliceType()->isMutable()) { //* note: same cheat here. auto ret = this->irb.Bitcast(from, target); result = ret; } else if(fromType->isTupleType() && target->isTupleType() && fromType->toTupleType()->getElementCount() == target->toTupleType()->getElementCount()) { // auto ftt = fromType->toTupleType(); auto ttt = target->toTupleType(); auto tuple = this->irb.CreateValue(target); bool failed = false; for(size_t i = 0; i < ttt->getElementCount(); i++) { auto res = this->oneWayAutocast(this->irb.ExtractValue(from, { i }), ttt->getElementN(i)); if(res == 0) { failed = true; break; } tuple = this->irb.InsertValue(tuple, { i }, res); } if(!failed) result = tuple; } else if(target->isAnyType()) { // great. auto fn = glue::any::generateCreateAnyWithValueFunction(this, from->getType()); iceAssert(fn); result = this->irb.Call(fn, from); } if(!result) { error(this->loc(), "unsupported autocast of '%s' -> '%s'", fromType, target); } else { if(fir::isRefCountedType(result->getType())) this->addRefCountedValue(result); return result; } } std::pair CodegenState::autoCastValueTypes(fir::Value* lhs, fir::Value* rhs) { auto lt = lhs->getType(); auto rt = rhs->getType(); if(lt == rt) { // if(lt->isConstantNumberType()) // { // // well. do the sensible default, i guess. // iceAssert(rt->isConstantNumberType()); // auto cnt = fir::unifyConstantTypes(lt->toConstantNumberType(), rt->toConstantNumberType()); // if(cnt->isFloating()) // return { this->irb.AppropriateCast(lhs, cnt), this->irb.AppropriateCast(rhs, cnt) }; // } return { lhs, rhs }; } // prefer to cast the void pointer to the other one, not the other way around. if(lt->isNullType() && rt->isPointerType()) return std::make_pair(this->irb.PointerTypeCast(lhs, rt), rhs); else if(lt->isPointerType() && rt->isNullType()) return std::make_pair(lhs, this->irb.PointerTypeCast(rhs, lt)); /* if(lt->isConstantNumberType() && !rt->isConstantNumberType()) { auto cn = dcast(fir::ConstantNumber, lhs); iceAssert(cn); auto res = _unwrapConstantNumber(this, cn, rt, true); if(!res) return { lhs, rhs }; else return { CGResult(res), rhs }; } else if(!lt->isConstantNumberType() && rt->isConstantNumberType()) { auto [ l, r ] = this->autoCastValueTypes(rhs, lhs); return { r, l }; } else */if(lt->isIntegerType() && rt->isIntegerType() && lt->isSignedIntType() == rt->isSignedIntType()) { // ok, neither are constants // do the normal thing if(lt->getBitWidth() > rt->getBitWidth()) { // cast rt to lt return { lhs, this->irb.IntSizeCast(rhs, lt) }; } else if(lt->getBitWidth() < rt->getBitWidth()) { return { this->irb.IntSizeCast(lhs, rt), rhs }; } else { return { lhs, rhs }; } } else if(lt->isFloatingPointType() && rt->isFloatingPointType()) { // ok, neither are constants // do the normal thing if(lt->getBitWidth() > rt->getBitWidth()) { // cast rt to lt return { lhs, this->irb.FExtend(rhs, lt) }; } else if(lt->getBitWidth() < rt->getBitWidth()) { return { this->irb.FExtend(lhs, rt), rhs }; } else { return { lhs, rhs }; } } // TODO: do we really want this? else if((lt->isFloatingPointType() && rt->isIntegerType()) || (rt->isFloatingPointType() && lt->isIntegerType())) { if(lt->isFloatingPointType()) return { lhs, this->irb.IntToFloatCast(rhs, lt) }; else return { this->irb.IntToFloatCast(lhs, rt), rhs }; } // nope... warn(this->loc(), "unsupported autocast of '%s' -> '%s'", lt, rt); return { 0, 0 }; } } ================================================ FILE: source/codegen/builtin.cpp ================================================ // builtin.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "errors.h" #include "codegen.h" #include "gluecode.h" #include "typecheck.h" // stupid c++, u don't do it with 'using' namespace names = strs::names; static fir::Value* checkNullPointerOrReturnZero(cgn::CodegenState* cs, fir::Value* ptr) { iceAssert(ptr->getType() == fir::Type::getNativeWordPtr()); auto isnull = cs->irb.ICmpEQ(ptr, fir::ConstantValue::getZeroValue(fir::Type::getNativeWordPtr())); auto prevb = cs->irb.getCurrentBlock(); auto deref = cs->irb.addNewBlockAfter("deref", prevb); auto merge = cs->irb.addNewBlockAfter("merge", deref); cs->irb.CondBranch(isnull, merge, deref); cs->irb.setCurrentBlock(deref); auto rc = cs->irb.ReadPtr(ptr); cs->irb.UnCondBranch(merge); cs->irb.setCurrentBlock(merge); auto phi = cs->irb.CreatePHINode(fir::Type::getNativeWord()); phi->addIncoming(fir::ConstantInt::getNative(0), prevb); phi->addIncoming(rc, deref); return phi; } CGResult sst::BuiltinDotOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); auto res = this->lhs->codegen(cs); auto ty = res.value->getType(); if(this->isFunctionCall) { std::vector arguments = zfu::map(this->args, [cs](sst::Expr* e) -> fir::Value* { return e->codegen(cs).value; }); if(this->name == names::saa::FN_CLONE) { iceAssert(arguments.empty()); auto clonef = cgn::glue::saa_common::generateCloneFunction(cs, ty); auto ret = cs->irb.Call(clonef, cs->irb.CreateSliceFromSAA(res.value, false), fir::ConstantInt::getNative(0)); iceAssert(fir::isRefCountedType(ret->getType())); cs->addRefCountedValue(ret); return CGResult(ret); } else if(this->name == names::array::FN_POP) { iceAssert(!ty->isStringType()); if(!res->islvalue()) error(this->lhs, "cannot call 'pop()' on an rvalue"); else if(res->isConst()) error(this->lhs, "cannot call 'pop()' (which mutates) on a constant value"); else if(ty->isArrayType()) error(this->lhs, "cannot call 'pop()' on an array type ('%s')", ty); auto popf = cgn::glue::array::getPopElementFromBackFunction(cs, ty); auto tupl = cs->irb.Call(popf, res.value, fir::ConstantCharSlice::get(this->loc.toString())); // tupl[0] is the new array // tupl[1] is the last element auto newarr = cs->irb.ExtractValue(tupl, { 0 }); auto retelm = cs->irb.ExtractValue(tupl, { 1 }); cs->irb.Store(newarr, res.value); return CGResult(retelm); } else if(this->name == names::saa::FN_APPEND) { iceAssert(arguments.size() == 1); if(!res->islvalue()) error(this->lhs, "cannot call 'append' on an rvalue"); auto arg = arguments[0]; fir::Function* appendf = cgn::glue::saa_common::generateAppropriateAppendFunction(cs, ty, arg->getType()); iceAssert(appendf); if(arg->getType()->isDynamicArrayType() && arg->getType() == ty) arg = cs->irb.CreateSliceFromSAA(arg, true); else if(arg->getType()->isStringType() && arg->getType() == ty) arg = cs->irb.CreateSliceFromSAA(arg, true); auto ret = cs->irb.Call(appendf, res.value, arg); cs->irb.Store(ret, res.value); return CGResult(res); } } else { if(ty->isStringType() || ty->isDynamicArrayType()) { if(this->name == names::saa::FIELD_POINTER) return CGResult(cs->irb.GetSAAData(res.value)); else if(this->name == names::saa::FIELD_LENGTH) return CGResult(cs->irb.GetSAALength(res.value)); else if(this->name == names::saa::FIELD_CAPACITY) return CGResult(cs->irb.GetSAACapacity(res.value)); else if(this->name == names::saa::FIELD_REFCOUNT) { return CGResult(checkNullPointerOrReturnZero(cs, cs->irb.GetSAARefCountPointer(res.value))); } else if(ty->isStringType() && this->name == names::string::FIELD_COUNT) { auto fn = cgn::glue::string::getUnicodeLengthFunction(cs); iceAssert(fn); auto ret = cs->irb.Call(fn, cs->irb.GetSAAData(res.value)); return CGResult(ret); } } else if(ty->isArraySliceType()) { if(this->name == names::saa::FIELD_LENGTH) return CGResult(cs->irb.GetArraySliceLength(res.value)); else if(this->name == names::saa::FIELD_POINTER) return CGResult(cs->irb.GetArraySliceData(res.value)); } else if(ty->isArrayType()) { if(this->name == names::saa::FIELD_LENGTH) { return CGResult(fir::ConstantInt::getNative(ty->toArrayType()->getArraySize())); } else if(this->name == names::saa::FIELD_POINTER) { // TODO: LVALUE HOLE if(res.value->islvalue()) { auto ret = cs->irb.ConstGEP2(cs->irb.AddressOf(res.value, /* mut: */ false), 0, 0); return CGResult(ret); } else { error("NOT SUP"); } } } else if(ty->isRangeType()) { if(this->name == names::range::FIELD_BEGIN) return CGResult(cs->irb.GetRangeLower(res.value)); else if(this->name == names::range::FIELD_END) return CGResult(cs->irb.GetRangeUpper(res.value)); else if(this->name == names::range::FIELD_STEP) return CGResult(cs->irb.GetRangeStep(res.value)); } else if(ty->isAnyType()) { if(this->name == names::any::FIELD_TYPEID) return CGResult(cs->irb.GetAnyTypeID(res.value)); else if(this->name == names::any::FIELD_REFCOUNT) return CGResult(checkNullPointerOrReturnZero(cs, cs->irb.GetAnyRefCountPointer(res.value))); } else if(ty->isEnumType()) { if(this->name == names::enumeration::FIELD_INDEX) { return CGResult(cs->irb.GetEnumCaseIndex(res.value)); } else if(this->name == names::enumeration::FIELD_VALUE) { return CGResult(cs->irb.GetEnumCaseValue(res.value)); } else if(this->name == names::enumeration::FIELD_NAME) { auto namearr = ty->toEnumType()->getNameArray(); iceAssert(namearr->islvalue()); auto namearrptr = cs->irb.AddressOf(namearr, /* mut: */ false); iceAssert(namearrptr->getType()->isPointerType() && namearrptr->getType()->getPointerElementType()->isArrayType()); auto idx = cs->irb.GetEnumCaseIndex(res.value); auto n = cs->irb.GEP2(namearrptr, fir::ConstantInt::getNative(0), idx); return CGResult(cs->irb.ReadPtr(n)); } } } error(this, "no property or builtin method '%s' on type '%s'", this->name, ty); } ================================================ FILE: source/codegen/call.cpp ================================================ // call.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include #include "sst.h" #include "memorypool.h" #include "codegen.h" #include "gluecode.h" util::hash_map cgn::CodegenState::getNameIndexMap(sst::FunctionDefn* fd) { util::hash_map idxmap; for(size_t i = 0; i < fd->params.size(); i++) idxmap[fd->params[i].name] = i; return idxmap; } static std::vector _codegenAndArrangeFunctionCallArguments(cgn::CodegenState* cs, fir::FunctionType* ft, const std::vector& arguments, const util::hash_map& idxmap, const util::hash_map& defaultArgumentValues) { bool fvararg = ft->isVariadicFunc(); size_t numNormalArgs = ft->getArgumentCount() + (fvararg ? -1 : 0); util::hash_map argExprs; util::hash_map revArgExprs; // this thing below operates similarly to the list solver in typecheck/polymorph/solver.cpp size_t last_arg = std::min(numNormalArgs, arguments.size()); size_t positionalCounter = 0; size_t varArgStart = numNormalArgs; for(size_t i = 0; i < last_arg; i++) { const auto& arg = arguments[i]; if(!arg.name.empty()) { auto it = idxmap.find(arg.name); iceAssert(it != idxmap.end()); argExprs[it->second] = arg.value; revArgExprs[arg.value] = it->second; if(defaultArgumentValues.find(it->second) == defaultArgumentValues.end()) positionalCounter++; } else { // so, `positionalCounter` counts the paramters on the declaration-side. thus, once we encounter a default value, // it must mean that the rest of the parameters will be optional as well. //* ie. we've passed all the positional arguments already, leaving the optional ones, which means every argument from //* here onwards (including this one) must be named. since this is *not* named, we just skip straight to the varargs if //* it was present. if(fvararg && defaultArgumentValues.find(positionalCounter) != defaultArgumentValues.end()) { varArgStart = i; break; } argExprs[positionalCounter] = arg.value; revArgExprs[arg.value] = positionalCounter; positionalCounter++; } } for(size_t i = 0; i < numNormalArgs; i++) { if(argExprs.find(i) == argExprs.end()) { auto it = defaultArgumentValues.find(i); if(it == defaultArgumentValues.end()) error(cs->loc(), "missing value for argument %d", i); argExprs[i] = it->second; revArgExprs[it->second] = i; } } auto doCastIfNecessary = [cs](const Location& loc, fir::Value* val, fir::Type* infer) -> fir::Value* { if(val->getType()->isConstantNumberType()) { auto cv = dcast(fir::ConstantValue, val); iceAssert(cv); val = cs->unwrapConstantNumber(cv); } if(!infer) return val; if(val->getType() != infer) { val = cs->oneWayAutocast(val, infer); if(val->getType() != infer) { auto errs = SpanError::make(SimpleError::make(loc, "mismatched type in function call; parameter has type '%s', " "but given argument has type '%s'", infer, val->getType())); errs->postAndQuit(); } } return val; }; std::vector values(argExprs.size()); { for(size_t i = 0; i < argExprs.size(); i++) { // this extra complexity is to ensure we codegen arguments from left-to-right! auto arg = argExprs[i]; auto k = revArgExprs[arg]; auto infer = ft->getArgumentN(k); auto val = arg->codegen(cs, infer).value; //! RAII: COPY CONSTRUCTOR CALL //? the copy constructor is called when passed as an argument to a function call //* copyRAIIValue will just return 'val' if it is not a class type, so we don't check it here! val = cs->copyRAIIValue(val); //* arguments are added to the refcounting list in the function, //* so we need to "pre-increment" the refcount here, so it does not //* get freed when the function returns. if(fir::isRefCountedType(val->getType())) cs->incrementRefCount(val); if(val->getType()->isConstantNumberType()) { auto cv = dcast(fir::ConstantValue, val); iceAssert(cv); val = cs->unwrapConstantNumber(cv); } val = doCastIfNecessary(arg->loc, val, infer); values[k] = val; } } // check the variadic arguments. note that IRBuilder will handle actually wrapping the values up into a slice // and/or creating an empty slice and/or forwarding an existing slice. we just need to supply the values. for(size_t i = varArgStart; i < arguments.size(); i++) { auto arg = arguments[i].value; fir::Type* infer = 0; if(fvararg) { auto vararrty = ft->getArgumentN(ft->getArgumentCount() - 1); // if forwarding perfectly, then infer as the slice type, instead of the element type. if(i == arguments.size() - 1 && arg->type->isVariadicArrayType()) { // perfect forwarding. infer = vararrty; } else { iceAssert(vararrty->isVariadicArrayType()); infer = vararrty->getArrayElementType(); } } auto val = arg->codegen(cs, infer).value; if(fir::isRefCountedType(val->getType())) cs->incrementRefCount(val); val = doCastIfNecessary(arg->loc, val, infer); if(ft->isCStyleVarArg()) { // auto-convert strings and char slices into char* when passing to va_args if(val->getType()->isStringType()) val = cs->irb.GetSAAData(val); else if(val->getType()->isCharSliceType()) val = cs->irb.GetArraySliceData(val); // also, see if we need to promote the type! // anything < int gets promoted to int; float -> double else if(val->getType() == fir::Type::getFloat32()) val = cs->irb.FExtend(val, fir::Type::getFloat64()); // don't need to worry about signedness for this; if you're smaller than int32, // int32 can represent you even if you're unsigned else if(val->getType()->isIntegerType() && val->getType()->toPrimitiveType()->getIntegerBitWidth() < 32) val = cs->irb.IntSizeCast(val, val->getType()->isSignedIntType() ? fir::Type::getInt32() : fir::Type::getUint32()); else if(val->getType()->isBoolType()) val = cs->irb.IntZeroExt(val, fir::Type::getInt32()); } values.push_back(val); } return values; } std::vector cgn::CodegenState::codegenAndArrangeFunctionCallArguments(sst::Defn* target, fir::FunctionType* ft, const std::vector& arguments) { util::hash_map idxmap; util::hash_map defaultArgs; if(auto fd = dcast(sst::FunctionDefn, target)) { idxmap = this->getNameIndexMap(fd); zfu::foreachIdx(fd->params, [&defaultArgs](const FnParam& arg, size_t idx) { if(arg.defaultVal) defaultArgs[idx] = arg.defaultVal; }); } return _codegenAndArrangeFunctionCallArguments(this, ft, arguments, idxmap, defaultArgs); } CGResult sst::FunctionCall::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); if(!this->target) error(this, "failed to find target for function call to '%s'", this->name); // check this target fir::Value* vf = 0; fir::FunctionType* ft = 0; if(dcast(VarDefn, this->target)) { // ok, we're calling a variable. // the below stuff ain't gonna work without some intervention CGResult defn; CGResult r = cs->valueMap[this->target]; if(r.value) { defn = r; } else if(cs->isInMethodBody()) { defn = cs->getStructFieldImplicitly(this->name); } else { error(this, "no such '%s'", this->name); } iceAssert(defn.value); vf = defn.value; } else if(auto fd = dcast(FunctionDefn, this->target); fd && fd->isVirtual) { // ok then. auto ret = cs->callVirtualMethod(this); cs->addRAIIOrRCValueIfNecessary(ret); return CGResult(ret); } else { vf = this->target->codegen(cs).value; } if(vf->getType()->isFunctionType()) { ft = vf->getType()->toFunctionType(); } else { // we should have disallowed this already in the typechecker. // TODO: is the usecase then to just cast to a function type? // eg. let entry = (0x400000) as (fn()->int) or something iceAssert(false && "somehow you got a pointer-to-function?!"); // auto vt = vf->getType(); // iceAssert(vt->isPointerType() && vt->getPointerElementType()->isFunctionType()); // ft = vt->getPointerElementType()->toFunctionType(); // warn(this, "prefer using functions to function pointers"); } iceAssert(ft); //! SELF HANDLING (INSERTION) (CODEGEN) if(auto fd = dcast(FunctionDefn, this->target); fd && fd->parentTypeForMethod && cs->isInMethodBody() && this->isImplicitMethodCall) { auto fake = util::pool(this->loc, fd->parentTypeForMethod->getPointerTo()); fake->rawValue = CGResult(cs->irb.AddressOf(cs->getMethodSelf(), true)); this->arguments.insert(this->arguments.begin(), FnCallArgument(this->loc, "this", fake, 0)); } size_t numArgs = ft->getArgumentCount(); if(ft->isCStyleVarArg() && this->arguments.size() < numArgs) { error(this, "need at least %d arguments to call variadic function '%s', only have %d", numArgs, this->name, this->arguments.size()); } auto args = cs->codegenAndArrangeFunctionCallArguments(this->target, ft, this->arguments); fir::Value* ret = 0; if(fir::Function* func = dcast(fir::Function, vf)) { ret = cs->irb.Call(func, args); } else if(vf->getType()->isFunctionType()) { ret = cs->irb.CallToFunctionPointer(vf, ft, args); } else { iceAssert(vf->getType()->getPointerElementType()->isFunctionType()); auto fptr = cs->irb.ReadPtr(vf); ret = cs->irb.CallToFunctionPointer(fptr, ft, args); } // do the refcounting if we need to cs->addRAIIOrRCValueIfNecessary(ret); return CGResult(ret); } static CGResult callBuiltinTypeConstructor(cgn::CodegenState* cs, fir::Type* type, const std::vector& args) { // for non-strings it's trivial if(args.empty()) { return CGResult(cs->getDefaultValue(type)); } else if(!type->isStringType()) { iceAssert(args.size() == 1); auto ret = cs->oneWayAutocast(args[0]->codegen(cs, type).value, type); if(type != ret->getType()) error(args[0], "mismatched type in builtin type initialiser; expected '%s', found '%s'", type, ret->getType()); return CGResult(ret); } else { auto cloneTheSlice = [cs](fir::Value* slc) -> CGResult { iceAssert(slc->getType()->isCharSliceType()); auto clonef = cgn::glue::string::getCloneFunction(cs); iceAssert(clonef); auto ret = cs->irb.Call(clonef, slc, fir::ConstantInt::getNative(0)); cs->addRefCountedValue(ret); return CGResult(ret); }; if(args.size() == 1) { iceAssert(args[0]->type->isCharSliceType()); return cloneTheSlice(args[0]->codegen(cs, fir::Type::getCharSlice(false)).value); } else { iceAssert(args.size() == 2); iceAssert(args[0]->type == fir::Type::getInt8Ptr() || args[0]->type == fir::Type::getMutInt8Ptr()); iceAssert(args[1]->type->isIntegerType()); auto ptr = args[0]->codegen(cs).value; auto len = cs->oneWayAutocast(args[1]->codegen(cs, fir::Type::getNativeWord()).value, fir::Type::getNativeWord()); auto slc = cs->irb.CreateValue(fir::Type::getCharSlice(false)); slc = cs->irb.SetArraySliceData(slc, (ptr->getType()->isMutablePointer() ? cs->irb.PointerTypeCast(ptr, fir::Type::getInt8Ptr()) : ptr)); slc = cs->irb.SetArraySliceLength(slc, len); return cloneTheSlice(slc); } } } CGResult sst::ExprCall::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); if(auto te = dcast(sst::TypeExpr, this->callee)) return callBuiltinTypeConstructor(cs, te->type, this->arguments); iceAssert(this->callee); fir::Value* fn = this->callee->codegen(cs).value; iceAssert(fn->getType()->isFunctionType()); auto ft = fn->getType()->toFunctionType(); if(ft->getArgumentCount() != this->arguments.size()) { if((!ft->isVariadicFunc() && !ft->isCStyleVarArg()) || this->arguments.size() < ft->getArgumentCount()) { error(this, "mismatched number of arguments; expected %d, but %d were given", ft->getArgumentCount(), this->arguments.size()); } } std::vector fcas = zfu::map(this->arguments, [](sst::Expr* arg) -> FnCallArgument { return FnCallArgument(arg->loc, "", arg, /* orig: */ nullptr); }); std::vector args = cs->codegenAndArrangeFunctionCallArguments(/* targetDefn: */ nullptr, ft, fcas); auto ret = cs->irb.CallToFunctionPointer(fn, ft, args); cs->addRAIIOrRCValueIfNecessary(ret); return CGResult(ret); } ================================================ FILE: source/codegen/classes.cpp ================================================ // classes.h // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "errors.h" #include "codegen.h" #include "typecheck.h" #include "memorypool.h" CGResult sst::ClassDefn::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); iceAssert(this->type && this->type->isClassType()); std::vector meths; std::vector inits; auto clsty = this->type->toClassType(); //* this looks stupid, but in 'setbaseclass' we update the virtual methods of the current class. //* since when we previously set the base class there were no virtual methods (we were still typechecking), //* we need to do it again. if(this->baseClass) { this->baseClass->codegen(cs); clsty->setBaseClass(clsty->getBaseClass()); } for(auto method : this->methods) { auto res = method->codegen(cs); auto f = dcast(fir::Function, res.value); meths.push_back(f); if(method->isVirtual) clsty->addVirtualMethod(f); if(method->id.name == "init") inits.push_back(f); if(method->id.name == "deinit") clsty->setDestructor(f); if(method->id.name == "copy") clsty->setCopyConstructor(f); if(method->id.name == "move") clsty->setMoveConstructor(f); } clsty->setMethods(meths); clsty->setInitialiserFunctions(inits); for(auto sm : this->staticFields) sm->codegen(cs); for(auto sm : this->staticMethods) sm->codegen(cs); for(auto nt : this->nestedTypes) nt->codegen(cs); auto restore = cs->irb.getCurrentBlock(); // make the inline initialiser { fir::Function* func = cs->module->getOrCreateFunction(fir::Name::obfuscate(clsty->encodedStr(), "_inline_init"), fir::FunctionType::get({ this->type->getMutablePointerTo() }, fir::Type::getVoid()), fir::LinkageType::Internal); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); auto self = cs->irb.Dereference(func->getArguments()[0], "this"); // make sure we call the base init first. if(clsty->getBaseClass()) { auto bii = clsty->getBaseClass()->getInlineInitialiser(); iceAssert(bii); cs->irb.Call(bii, cs->irb.PointerTypeCast(cs->irb.AddressOf(self, true), clsty->getBaseClass()->getMutablePointerTo())); } // set our vtable if(clsty->getVirtualMethodCount() > 0) { auto vtable = cs->irb.PointerTypeCast(cs->irb.AddressOf(cs->module->getOrCreateVirtualTableForClass(clsty), false), fir::Type::getInt8Ptr()); cs->irb.SetVtable(self, vtable); } for(auto fd : this->fields) { if(fd->init) { auto res = fd->init->codegen(cs, fd->type).value; auto elmptr = cs->irb.GetStructMember(self, fd->id.name); cs->autoAssignRefCountedValue(elmptr, res, true); } else { auto elmptr = cs->irb.GetStructMember(self, fd->id.name); cs->autoAssignRefCountedValue(elmptr, cs->getDefaultValue(fd->type), true); } } cs->irb.ReturnVoid(); clsty->setInlineInitialiser(func); } // this is the inline destructor { fir::Function* func = cs->module->getOrCreateFunction(fir::Name::obfuscate(clsty->encodedStr(), "_inline_deinit"), fir::FunctionType::get({ this->type->getMutablePointerTo() }, fir::Type::getVoid()), fir::LinkageType::Internal); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); auto selfptr = func->getArguments()[0]; auto self = cs->irb.Dereference(selfptr, "this"); for(auto f : this->fields) { if(f->type->isClassType()) { auto fld = cs->irb.GetStructMember(self, f->id.name); cs->callDestructor(fld); } } // ok, now that we have destroyed our own fields, call the base class destructor, followed by the base class inline destructor! if(auto base = clsty->getBaseClass(); base) { auto baseptr = cs->irb.PointerTypeCast(selfptr, base->getMutablePointerTo()); if(auto des = base->getDestructor(); des) cs->irb.Call(des, baseptr); cs->irb.Call(base->getInlineDestructor(), baseptr); } cs->irb.ReturnVoid(); clsty->setInlineDestructor(func); } cs->irb.setCurrentBlock(restore); return CGResult(0); } fir::Value* cgn::CodegenState::callVirtualMethod(sst::FunctionCall* call) { auto fd = dcast(sst::FunctionDefn, call->target); iceAssert(fd); auto cls = fd->parentTypeForMethod->toClassType(); iceAssert(cls); if(call->isImplicitMethodCall) { iceAssert(this->isInMethodBody() && fd->parentTypeForMethod); auto fake = util::pool(call->loc, fd->parentTypeForMethod->getPointerTo()); fake->rawValue = CGResult(this->irb.AddressOf(this->getMethodSelf(), /* mutable: */ true)); //! SELF HANDLING (INSERTION) (CODEGEN) call->arguments.insert(call->arguments.begin(), FnCallArgument(call->loc, "this", fake, 0)); } iceAssert(fd->type->isFunctionType()); auto ft = fd->type->toFunctionType(); auto args = this->codegenAndArrangeFunctionCallArguments(fd, ft, call->arguments); auto idx = cls->getVirtualMethodIndex(call->name, ft); return this->irb.CallVirtualMethod(cls, ft, idx, args); } ================================================ FILE: source/codegen/codegenstate.cpp ================================================ // codegenstate.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "errors.h" #include "codegen.h" #include "platform.h" #include "gluecode.h" #include "typecheck.h" namespace cgn { void CodegenState::enterMethodBody(fir::Function* method, fir::Value* self) { this->methodSelfStack.push_back(self); auto ty = self->getType(); iceAssert(ty->isClassType() || ty->isStructType()); this->methodList[method] = ty; } void CodegenState::leaveMethodBody() { iceAssert(this->methodSelfStack.size() > 0); this->methodSelfStack.pop_back(); } bool CodegenState::isInMethodBody() { return this->methodSelfStack.size() > 0 && this->functionStack.size() > 0 && this->methodList.find(this->functionStack.back()) != this->methodList.end(); } fir::Value* CodegenState::getMethodSelf() { iceAssert(this->methodSelfStack.size() > 0); return this->methodSelfStack.back(); } void CodegenState::enterSubscriptWithLength(fir::Value* len) { iceAssert(len->getType()->isIntegerType()); this->subscriptArrayLengthStack.push_back(len); } fir::Value* CodegenState::getCurrentSubscriptArrayLength() { iceAssert(this->subscriptArrayLengthStack.size() > 0); return this->subscriptArrayLengthStack.back(); } void CodegenState::leaveSubscript() { iceAssert(this->subscriptArrayLengthStack.size() > 0); this->subscriptArrayLengthStack.pop_back(); } void CodegenState::enterFunction(fir::Function* fn) { this->functionStack.push_back(fn); } void CodegenState::leaveFunction() { if(this->functionStack.empty()) error(this->loc(), "not a in function"); this->functionStack.pop_back(); } fir::Function* CodegenState::getCurrentFunction() { if(this->functionStack.empty()) error(this->loc(), "not a in function"); return this->functionStack.back(); } ControlFlowPoint CodegenState::getCurrentCFPoint() { return this->breakingPointStack.back(); } void CodegenState::enterBreakableBody(const ControlFlowPoint& cfp) { // only the block needs to exist. iceAssert(cfp.block); this->breakingPointStack.push_back(cfp); } ControlFlowPoint CodegenState::leaveBreakableBody() { iceAssert(this->breakingPointStack.size() > 0); auto ret = this->breakingPointStack.back(); this->breakingPointStack.pop_back(); return ret; } BlockPoint CodegenState::getCurrentBlockPoint() { return this->blockPointStack.back(); } void CodegenState::enterBlock(const BlockPoint& bp) { iceAssert(bp.block); this->blockPointStack.push_back(bp); } void CodegenState::leaveBlock() { iceAssert(this->blockPointStack.size() > 0); this->blockPointStack.pop_back(); } void CodegenState::pushLoc(const Location& l) { this->locationStack.push_back(l); } void CodegenState::pushLoc(sst::Stmt* stmt) { this->pushLoc(stmt->loc); } void CodegenState::popLoc() { iceAssert(this->locationStack.size() > 0); this->locationStack.pop_back(); } Location CodegenState::loc() { iceAssert(this->locationStack.size() > 0); return this->locationStack.back(); } void CodegenState::createWhileLoop(const std::function& docheck, const std::function& dobody) { fir::IRBlock* check = this->irb.addNewBlockInFunction("check", this->irb.getCurrentFunction()); fir::IRBlock* body = this->irb.addNewBlockInFunction("body", this->irb.getCurrentFunction()); fir::IRBlock* merge = this->irb.addNewBlockInFunction("merge", this->irb.getCurrentFunction()); this->irb.UnCondBranch(check); this->irb.setCurrentBlock(check); //* we expect this to do its own branching. docheck(body, merge); this->irb.setCurrentBlock(body); dobody(); //* but not the body. this->irb.UnCondBranch(check); //* back to regularly scheduled programming this->irb.setCurrentBlock(merge); } fir::Value* CodegenState::getDefaultValue(fir::Type* type) { fir::Value* ret = 0; if(type->isStringType()) { fir::Value* arr = this->irb.CreateValue(type); arr = this->irb.SetSAAData(arr, this->irb.PointerTypeCast(this->irb.GetArraySliceData(fir::ConstantCharSlice::get("")), fir::Type::getMutInt8Ptr())); arr = this->irb.SetSAALength(arr, fir::ConstantInt::getNative(0)); arr = this->irb.SetSAACapacity(arr, fir::ConstantInt::getNative(0)); arr = this->irb.SetSAARefCountPointer(arr, fir::ConstantValue::getZeroValue(fir::Type::getNativeWord()->getPointerTo())); ret = arr; } else if(type->isDynamicArrayType()) { fir::Value* arr = this->irb.CreateValue(type); arr = this->irb.SetSAAData(arr, fir::ConstantValue::getZeroValue(type->getArrayElementType()->getMutablePointerTo())); arr = this->irb.SetSAALength(arr, fir::ConstantInt::getNative(0)); arr = this->irb.SetSAACapacity(arr, fir::ConstantInt::getNative(0)); arr = this->irb.SetSAARefCountPointer(arr, fir::ConstantValue::getZeroValue(fir::Type::getNativeWord()->getPointerTo())); ret = arr; } else if(type->isArraySliceType()) { fir::Value* arr = this->irb.CreateValue(type); arr = this->irb.SetArraySliceData(arr, fir::ConstantValue::getZeroValue(type->getArrayElementType()->getPointerTo())); arr = this->irb.SetArraySliceLength(arr, fir::ConstantInt::getNative(0)); ret = arr; } else if(type->isClassType()) { // TODO //! use constructClassWithArguments!!! auto clsdef = dcast(sst::ClassDefn, this->typeDefnMap[type]); iceAssert(clsdef); clsdef->codegen(this); // first need to check if we have any initialisers with 0 parameters. auto cls = type->toClassType(); sst::FunctionDefn* ifn = 0; for(auto init : clsdef->initialisers) { //* note: count == 1 because of 'self' if(init->arguments.size() == 1) { ifn = init; break; } } if(ifn == 0) { SimpleError::make(this->loc(), "class '%s' cannot be automatically initialised as it does not have a constructor taking 0 arguments", cls->getTypeName())->append(SimpleError::make(MsgType::Note, clsdef->loc, "class '%s' was defined here:", clsdef->id.name)) ->postAndQuit(); } ret = this->constructClassWithArguments(cls, ifn, { }); } else { ret = fir::ConstantValue::getZeroValue(type); } if(fir::isRefCountedType(type)) this->addRefCountedValue(ret); ret->setKind(fir::Value::Kind::prvalue); return ret; } void CodegenState::pushIRDebugIndentation() { this->_debugIRIndent++; } void CodegenState::printIRDebugMessage(const std::string& msg, const std::vector& vals) { fir::Value* tmpstr = this->module->createGlobalString(std::string(this->_debugIRIndent * 4, ' ') + msg + "\n"); this->irb.Call(this->getOrDeclareLibCFunction("printf"), tmpstr + vals); } void CodegenState::popIRDebugIndentation() { this->_debugIRIndent--; } fir::Function* CodegenState::getOrDeclareLibCFunction(std::string name) { if(name == ALLOCATE_MEMORY_FUNC) { return this->module->getOrCreateFunction(fir::Name::of(ALLOCATE_MEMORY_FUNC), fir::FunctionType::get({ fir::Type::getNativeWord() }, fir::Type::getMutInt8Ptr()), fir::LinkageType::External); } else if(name == FREE_MEMORY_FUNC) { return this->module->getOrCreateFunction(fir::Name::of(FREE_MEMORY_FUNC), fir::FunctionType::get({ fir::Type::getMutInt8Ptr() }, fir::Type::getVoid()), fir::LinkageType::External); } else if(name == REALLOCATE_MEMORY_FUNC) { return this->module->getOrCreateFunction(fir::Name::of(REALLOCATE_MEMORY_FUNC), fir::FunctionType::get({ fir::Type::getMutInt8Ptr(), fir::Type::getNativeWord() }, fir::Type::getMutInt8Ptr()), fir::LinkageType::External); } else if(name == CRT_FDOPEN) { return this->module->getOrCreateFunction(fir::Name::of(CRT_FDOPEN), fir::FunctionType::get({ fir::Type::getInt32(), fir::Type::getInt8Ptr() }, fir::Type::getVoidPtr()), fir::LinkageType::External); } else if(name == "printf") { return this->module->getOrCreateFunction(fir::Name::of("printf"), fir::FunctionType::getCVariadicFunc({ fir::Type::getInt8Ptr() }, fir::Type::getInt32()), fir::LinkageType::External); } else if(name == "abort") { return this->module->getOrCreateFunction(fir::Name::of("abort"), fir::FunctionType::get({ }, fir::Type::getVoid()), fir::LinkageType::External); } else if(name == "exit") { return this->module->getOrCreateFunction(fir::Name::of("exit"), fir::FunctionType::get({ fir::Type::getInt32() }, fir::Type::getVoid()), fir::LinkageType::External); } else if(name == "strlen") { return this->module->getOrCreateFunction(fir::Name::of("strlen"), fir::FunctionType::get({ fir::Type::getInt8Ptr() }, fir::Type::getNativeWord()), fir::LinkageType::External); } else if(name == "fprintf") { return this->module->getOrCreateFunction(fir::Name::of("fprintf"), fir::FunctionType::getCVariadicFunc({ fir::Type::getVoidPtr(), fir::Type::getInt8Ptr() }, fir::Type::getInt32()), fir::LinkageType::External); } else if(name == "fflush") { return this->module->getOrCreateFunction(fir::Name::of("fflush"), fir::FunctionType::get({ fir::Type::getVoidPtr() }, fir::Type::getInt32()), fir::LinkageType::External); } else { error("enotsup: %s", name); } } bool CodegenState::isWithinGlobalInitFunction() { return this->isInsideGlobalInitFunc; } fir::IRBlock* CodegenState::enterGlobalInitFunction(fir::GlobalValue* val) { if(this->isInsideGlobalInitFunc) error(this->loc(), "unsynchronised use of global init function!!! (entering when already inside)"); auto ret = this->irb.getCurrentBlock(); { fir::Function* func = this->module->getOrCreateFunction( fir::Name::obfuscate(zpr::sprint("%s_piece_%d", strs::names::GLOBAL_INIT_FUNCTION, this->globalInitPieces.size())), fir::FunctionType::get({ }, fir::Type::getVoid()), fir::LinkageType::Internal); auto b = this->irb.addNewBlockInFunction("b", func); this->irb.setCurrentBlock(b); this->globalInitPieces.push_back(std::make_pair(val, func)); } this->isInsideGlobalInitFunc = true; return ret; } void CodegenState::leaveGlobalInitFunction(fir::IRBlock* restore) { if(!this->isInsideGlobalInitFunc) error(this->loc(), "unsynchronised use of global init function!!! (leaving when not inside)"); // terminate the current function. this->irb.ReturnVoid(); this->irb.setCurrentBlock(restore); this->isInsideGlobalInitFunc = false; } void CodegenState::finishGlobalInitFunction() { if(this->finalisedGlobalInitFunction != 0) { // clear all the blocks from it. for(auto b : this->finalisedGlobalInitFunction->getBlockList()) delete b; this->finalisedGlobalInitFunction->getBlockList().clear(); } else { this->finalisedGlobalInitFunction = this->module->getOrCreateFunction( fir::Name::obfuscate(strs::names::GLOBAL_INIT_FUNCTION), fir::FunctionType::get({ }, fir::Type::getVoid()), fir::LinkageType::Internal); } auto restore = this->irb.getCurrentBlock(); // ok, now we can do some stuff. // what we wanna do is just call all the "piece" global init functions that we made with enter/leave. // but, this function has no blocks (either cos it's new, or we deleted them all). so, make one. auto blk = this->irb.addNewBlockInFunction("entry", this->finalisedGlobalInitFunction); this->irb.setCurrentBlock(blk); for(auto piece : this->globalInitPieces) this->irb.Call(piece.second); // ok now return this->irb.ReturnVoid(); this->irb.setCurrentBlock(restore); } } ================================================ FILE: source/codegen/constructor.cpp ================================================ // constructor.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "sst.h" #include "codegen.h" #include "memorypool.h" fir::Value* cgn::CodegenState::getConstructedStructValue(fir::StructType* str, const std::vector& args) { fir::Value* value = this->irb.CreateValue(str); // set the arguments. if(args.size() > 0) { bool names = !args[0].name.empty(); // i just keeps track of the index in case we're not using names. size_t i = 0; for(const auto& arg : args) { if(names) { iceAssert(str->hasElementWithName(arg.name)); auto elmty = str->getElement(arg.name); value = this->irb.InsertValueByName(value, arg.name, arg.value->codegen(this, elmty).value); } else { iceAssert(str->getElementCount() > i); auto elmty = str->getElementN(i); value = this->irb.InsertValue(value, { i }, arg.value->codegen(this, elmty).value); } i++; } } if(fir::isRefCountedType(str)) this->addRefCountedValue(value); return value; } fir::Value* cgn::CodegenState::constructClassWithArguments(fir::ClassType* cls, sst::FunctionDefn* constr, const std::vector& args) { if(auto c = this->typeDefnMap[cls]) c->codegen(this); auto initfn = cls->getInlineInitialiser(); iceAssert(initfn); auto constrfn = dcast(fir::Function, constr->codegen(this, cls).value); iceAssert(constrfn); // this is dirty, very fucking dirty!!! std::vector vargs; { auto copy = args; auto fake = util::pool(this->loc(), cls->getMutablePointerTo()); fake->rawValue = CGResult(fir::ConstantValue::getZeroValue(cls->getMutablePointerTo())); //? what we are doing here is inserting a fake argument to placate `codegenAndArrangeFunctionCallArguments`, so that //? it does not error. this just allows us to get *THE REST* of the values in the correct order and generated appropriately, //? so that we can use their values and get their types below. copy.insert(copy.begin(), FnCallArgument(this->loc(), "this", fake, 0)); vargs = this->codegenAndArrangeFunctionCallArguments(constr, constrfn->getType(), copy); // for sanity, assert that it did not change. We should not have to cast anything, and "this" is always the first // argument in a constructor anyway! iceAssert(vargs[0] == fake->rawValue.value); // after we are done with that shennanigans, erase the first thing, which is the 'this', which doesn't really // exist here! vargs.erase(vargs.begin()); } // make a wrapper... auto fname = fir::Name::obfuscate("init_wrapper", constr->id.str()); fir::Function* wrapper_func = this->module->getFunction(fname); if(!wrapper_func) { auto restore = this->irb.getCurrentBlock(); auto arglist = zfu::map(vargs, [](fir::Value* v) -> auto { return v->getType(); }); wrapper_func = this->module->getOrCreateFunction(fname, fir::FunctionType::get(arglist, cls), fir::LinkageType::Internal); fir::IRBlock* entry = this->irb.addNewBlockInFunction("entry", wrapper_func); this->irb.setCurrentBlock(entry); // make the self: auto selfptr = this->irb.StackAlloc(cls, "self"); std::vector argvals = zfu::map(wrapper_func->getArguments(), [](auto a) -> fir::Value* { return a; }); argvals.insert(argvals.begin(), selfptr); this->irb.Call(initfn, selfptr); this->irb.Call(constrfn, argvals); this->irb.Return(this->irb.ReadPtr(selfptr)); this->irb.setCurrentBlock(restore); } if(vargs.size() != wrapper_func->getArgumentCount()) { SimpleError::make(this->loc(), "mismatched number of arguments in constructor call to class '%s'; expected %d, found %d instead", cls, constrfn->getArgumentCount(), vargs.size()) ->append(SimpleError::make(MsgType::Note, constr->loc, "constructor was defined here:")) ->postAndQuit(); } auto ret = this->irb.Call(wrapper_func, vargs); this->addRAIIValue(ret); return ret; } CGResult sst::StructConstructorCall::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); this->target->codegen(cs); if(!this->target) error(this, "failed to find target type of constructor call"); //* note: we don't need an explicit thing telling us whether we should use names or not //* if the first argument has no name, then we're not using names; if it has a name, then we are //* and ofc expect consistency, but we should have already typechecked that previously. StructDefn* str = dcast(StructDefn, this->target); if(!str) error(this, "non-struct type '%s' not supported in constructor call", this->target->id.name); // great. now we just make the thing. fir::Value* value = cs->getConstructedStructValue(str->type->toStructType(), this->arguments); return CGResult(value); } CGResult sst::ClassConstructorCall::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); this->classty->codegen(cs); auto cls = this->classty->type->toClassType(); auto ret = cs->constructClassWithArguments(cls, this->target, this->arguments); if(fir::isRefCountedType(cls)) cs->addRefCountedValue(ret); return CGResult(ret); } CGResult sst::BaseClassConstructorCall::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); this->classty->codegen(cs); auto cls = this->classty->type; auto self = cs->getMethodSelf(); iceAssert(self->getType()->isClassType()); auto selfty = self->getType()->toClassType(); iceAssert(selfty->getBaseClass()); auto basety = selfty->getBaseClass(); // just do it manually here: since we already have a self pointer, we can call the base class constructor function // directly. plus, we are not calling the inline initialiser also. { auto constrfn = dcast(fir::Function, this->target->codegen(cs, cls).value); iceAssert(constrfn); auto copy = this->arguments; auto selfptr = util::pool(this->loc, selfty->getMutablePointerTo()); selfptr->rawValue = CGResult(cs->irb.PointerTypeCast(cs->irb.AddressOf(cs->getMethodSelf(), /* mutable: */ true), basety->getMutablePointerTo())); copy.insert(copy.begin(), FnCallArgument(this->loc, "this", selfptr, 0)); std::vector vargs = cs->codegenAndArrangeFunctionCallArguments(this->target, constrfn->getType(), copy); cs->irb.Call(constrfn, vargs); } return CGResult(0); } ================================================ FILE: source/codegen/controlflow.cpp ================================================ // controlflow.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "sst.h" #include "codegen.h" #include "gluecode.h" // just a tmp thing static bool operator == (const sst::IfStmt::Case& a, const sst::IfStmt::Case& b) { return (a.body == b.body && a.cond == b.cond && a.inits == b.inits); } CGResult sst::IfStmt::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); fir::IRBlock* mergeblk = 0; auto trueblk = cs->irb.addNewBlockAfter("trueCase-" + this->loc.shortString(), cs->irb.getCurrentBlock()); if(!this->elideMergeBlock) mergeblk = cs->irb.addNewBlockAfter("mergeCase-" + this->loc.shortString(), trueblk); else iceAssert(this->elseCase); fir::IRBlock* elseblk = 0; if(this->elseCase) elseblk = cs->irb.addNewBlockAfter("elseCase-" + this->elseCase->loc.shortString(), trueblk); else elseblk = mergeblk; // first we gotta do all the inits of all the cases first. // we're already in our own scope, so it shouldn't matter. for(auto c : this->cases) for(auto i : c.inits) i->codegen(cs); // at the current place, first do the cond. iceAssert(this->cases.size() > 0); fir::Value* firstCond = cs->oneWayAutocast(this->cases.front().cond->codegen(cs, fir::Type::getBool()).value, fir::Type::getBool()); iceAssert(firstCond); if(!firstCond->getType()->isBoolType()) error(this->cases.front().cond, "non-boolean type '%s' cannot be used as a conditional", firstCond->getType()); // do a comparison // don't be stupid and cmp bool == true fir::Value* cmpRes = firstCond; auto restore = cs->irb.getCurrentBlock(); //! ACHTUNG ! //* we are not finished here; we will come back and insert an appropriate branch later. // now, then. cs->irb.setCurrentBlock(trueblk); { auto c = this->cases.front(); c.body->codegen(cs); if(cs->irb.getCurrentBlock() != nullptr && !cs->irb.getCurrentBlock()->isTerminated()) cs->irb.UnCondBranch(mergeblk); } // ok -- we don't really need to do it recursively, do we? auto remaining = std::vector(this->cases.begin() + 1, this->cases.end()); if(remaining.size() > 0) { // this block serves the purpose of initialising the conditions and stuff auto falseblk = cs->irb.addNewBlockAfter("falseCase-" + remaining[0].body->loc.shortString(), trueblk); { //* the patching -- if we have 'else-if' cases. cs->irb.setCurrentBlock(restore); cs->irb.CondBranch(cmpRes, trueblk, falseblk); } cs->irb.setCurrentBlock(falseblk); for(auto elif : remaining) { auto cond = cs->oneWayAutocast(elif.cond->codegen(cs, fir::Type::getBool()).value, fir::Type::getBool()); iceAssert(cond); if(!cond->getType()->isBoolType()) error(elif.cond, "non-boolean type '%s' cannot be used as a conditional", cond->getType()); // ok auto trueblk = cs->irb.addNewBlockAfter("trueCase-" + elif.body->loc.shortString(), cs->irb.getCurrentBlock()); fir::IRBlock* falseblkr = 0; if(elif == remaining.back()) falseblkr = elseblk; else falseblkr = cs->irb.addNewBlockAfter("falseCase-" + elif.body->loc.shortString(), cs->irb.getCurrentBlock()); fir::Value* cmpr = cond; cs->irb.CondBranch(cmpr, trueblk, falseblkr); cs->irb.setCurrentBlock(trueblk); { elif.body->codegen(cs); if(!cs->irb.getCurrentBlock()->isTerminated()) cs->irb.UnCondBranch(mergeblk); } cs->irb.setCurrentBlock(falseblkr); { // TODO: why tf is this commented out?? // ok, do the next thing. // if we're the last block, then gtfo and branch to merge // if() // { // if(!cs->irb.getCurrentBlock()->isTerminated()) // cs->irb.UnCondBranch(elseblk); // break; // } } } } else { //* the patching -- if we have no 'else-if' cases. cs->irb.setCurrentBlock(restore); cs->irb.CondBranch(cmpRes, trueblk, elseblk); } cs->irb.setCurrentBlock(elseblk); { if(this->elseCase) this->elseCase->codegen(cs); if(elseblk != mergeblk && !cs->irb.getCurrentBlock()->isTerminated()) cs->irb.UnCondBranch(mergeblk); } if(mergeblk) cs->irb.setCurrentBlock(mergeblk); // if we were supposed to elide the merge block, it means we have no more stuff after us. // tell our parent block this -- so that it can skip any extraneous codegen, eg: // fn x() { if true { return } else { return } return } // the last 'return' will cause a problem in IR generation if we don't skip it. return CGResult(0, this->elideMergeBlock ? CGResult::VK::EarlyOut : CGResult::VK::Normal); } std::vector sst::IfStmt::getBlocks() { std::vector ret; for(auto c : this->cases) ret.push_back(c.body); if(this->elseCase) ret.push_back(this->elseCase); return ret; } static void doBlockEndThings(cgn::CodegenState* cs, const cgn::ControlFlowPoint& cfp, const cgn::BlockPoint& bp) { #if DEBUG_ARRAY_REFCOUNTING | DEBUG_STRING_REFCOUNTING { cs->printIRDebugMessage("\n! CTRLFLOW: at: " + cfp.block->loc.shortString() + "\n{", { }); cs->pushIRDebugIndentation(); } #endif // then do the defers for(auto stmt : cfp.block->deferred) stmt->_codegen(cs); for(auto c : bp.raiiValues) cs->callDestructor(c); for(auto v : bp.refCountedValues) cs->decrementRefCount(v); #if DEBUG_ARRAY_REFCOUNTING | DEBUG_STRING_REFCOUNTING { cs->popIRDebugIndentation(); cs->printIRDebugMessage("}", { }); } #endif } CGResult sst::BreakStmt::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); auto bp = cs->getCurrentCFPoint().breakPoint; iceAssert(bp); // do the necessary doBlockEndThings(cs, cs->getCurrentCFPoint(), cs->getCurrentBlockPoint()); cs->irb.UnCondBranch(bp); return CGResult(0, CGResult::VK::EarlyOut); } CGResult sst::ContinueStmt::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); auto cp = cs->getCurrentCFPoint().continuePoint; iceAssert(cp); // do the necessary doBlockEndThings(cs, cs->getCurrentCFPoint(), cs->getCurrentBlockPoint()); cs->irb.UnCondBranch(cp); return CGResult(0, CGResult::VK::EarlyOut); } CGResult sst::ReturnStmt::_codegen(cgn::CodegenState* cs, fir::Type* infer) { // check if we have a value, and whether it's refcounted // if so, inflate its refcount so it doesn't get deallocated and can survive if(this->value) { auto v = this->value->codegen(cs, this->expectedType).value; if(fir::isRefCountedType(v->getType())) cs->incrementRefCount(v); if(v->getType() != this->expectedType) v = cs->oneWayAutocast(v, this->expectedType); //! RAII: COPY CONSTRUCTOR CALL //? the copy constructor is called when a function returns an object by value if(v->getType()->isClassType()) v = cs->copyRAIIValue(v); doBlockEndThings(cs, cs->getCurrentCFPoint(), cs->getCurrentBlockPoint()); cs->irb.Return(v); } else { doBlockEndThings(cs, cs->getCurrentCFPoint(), cs->getCurrentBlockPoint()); iceAssert(this->expectedType->isVoidType()); cs->irb.ReturnVoid(); } return CGResult(0, CGResult::VK::EarlyOut); } CGResult sst::Block::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); cs->enterBlock(this); defer(cs->leaveBlock()); if(this->preBodyCode) this->preBodyCode(); bool broke = false; for(auto stmt : this->statements) { auto res = stmt->codegen(cs); if(res.kind == CGResult::VK::EarlyOut) { broke = true; break; } } if(this->postBodyCode) this->postBodyCode(); // the reason we check for !broke here before doing the block cleanup is because BreakStmt // and ContinueStmt will do it too. if(!broke) { #if DEBUG_ARRAY_REFCOUNTING | DEBUG_STRING_REFCOUNTING { cs->printIRDebugMessage("\n! BLOCKEND: at: " + this->closingBrace.shortString() + "\n{", { }); cs->pushIRDebugIndentation(); } #endif //* this duplicates stuff from doBlockEndThings!! for(auto it = this->deferred.rbegin(); it != this->deferred.rend(); it++) (*it)->_codegen(cs); for(auto c : cs->getCurrentBlockPoint().raiiValues) cs->callDestructor(c); for(auto v : cs->getRefCountedValues()) cs->decrementRefCount(v); #if DEBUG_ARRAY_REFCOUNTING | DEBUG_STRING_REFCOUNTING { cs->popIRDebugIndentation(); cs->printIRDebugMessage("}", { }); } #endif } return CGResult(0); } ================================================ FILE: source/codegen/destructure.cpp ================================================ // destructure.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "sst.h" #include "codegen.h" #include "gluecode.h" #include "memorypool.h" CGResult sst::DecompDefn::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); cs->generateDecompositionBindings(this->bindings, this->init->codegen(cs), true); return CGResult(0); } static void handleDefn(cgn::CodegenState* cs, sst::VarDefn* defn, CGResult res) { // do a quick check for refcounting. //* note: due to the way vardefn codegen works, if we're assigning from an rvalue and the type is refcounted, //* we simply remove the rhs from the refcounting stack instead of changing refcounts around. //* so, since everything that we generate from destructuring is an rvalue, we always need to remove it. //* thus in order to remove it, we must first insert it. //* also, since the vardefn adds itself to the counting stack, when it dies we will get decremented. //* however, this cannot be allowed to happen, because we want a copy and not a move. if(fir::isRefCountedType(res->getType())) { cs->addRefCountedValue(res.value); cs->incrementRefCount(res.value); } if(defn) { auto v = util::pool(defn->loc, res.value->getType()); v->rawValue = res; defn->init = v; defn->codegen(cs); } } static void checkTuple(cgn::CodegenState* cs, const DecompMapping& bind, CGResult rhs) { iceAssert(!bind.array); auto rt = rhs.value->getType(); iceAssert(rt->isTupleType()); auto tty = rt->toTupleType(); iceAssert(bind.inner.size() == tty->getElementCount()); for(size_t i = 0; i < tty->getElementCount(); i++) { CGResult v; if(rhs->islvalue()) { auto gep = cs->irb.StructGEP(rhs.value, i); v = CGResult(gep); } else { v = CGResult(cs->irb.ExtractValue(rhs.value, { i })); } cs->generateDecompositionBindings(bind.inner[i], v, true); } } static void checkArray(cgn::CodegenState* cs, const DecompMapping& bind, CGResult rhs) { iceAssert(bind.array); auto rt = rhs.value->getType(); bool shouldSliceBeMutable = sst::getMutabilityOfSliceOfType(rt); if(!rt->isArrayType() && !rt->isDynamicArrayType() && !rt->isArraySliceType() && !rt->isStringType()) error(bind.loc, "expected array type in destructuring declaration; found type '%s' instead", rt); if(rt->isStringType()) { // do a bounds check. auto numbinds = fir::ConstantInt::getNative(bind.inner.size()); { auto checkf = cgn::glue::string::getBoundsCheckFunction(cs, true); if(checkf) { auto strloc = fir::ConstantCharSlice::get(bind.loc.toString()); cs->irb.Call(checkf, cs->irb.GetSAALength(rhs.value), numbinds, strloc); } } //* note: special-case this, because 1. we want to return chars auto strdat = cs->irb.PointerTypeCast(cs->irb.GetSAAData(rhs.value), fir::Type::getMutInt8Ptr()); { size_t idx = 0; for(auto& b : bind.inner) { auto v = CGResult(cs->irb.ReadPtr(cs->irb.GetPointer(strdat, fir::ConstantInt::getNative(idx)))); cs->generateDecompositionBindings(b, v, false); idx++; } } if(!bind.restName.empty()) { if(bind.restRef) { // make a slice of char. auto remaining = cs->irb.Subtract(cs->irb.GetSAALength(rhs.value), numbinds); auto slice = cs->irb.CreateValue(fir::Type::getCharSlice(shouldSliceBeMutable)); slice = cs->irb.SetArraySliceData(slice, cs->irb.GetPointer(strdat, numbinds)); slice = cs->irb.SetArraySliceLength(slice, remaining); handleDefn(cs, bind.restDefn, CGResult(slice)); } else { // make string. // auto remaining = cs->irb.Subtract(cs->irb.GetSAALength(rhs.value), numbinds); auto clonef = cgn::glue::string::getCloneFunction(cs); iceAssert(clonef); auto string = cs->irb.Call(clonef, rhs.value, numbinds); handleDefn(cs, bind.restDefn, CGResult(string)); } } } else { auto array = rhs.value; fir::Value* arrlen = 0; auto numbinds = fir::ConstantInt::getNative(bind.inner.size()); { if(rt->isArrayType()) arrlen = fir::ConstantInt::getNative(rt->toArrayType()->getArraySize()); else if(rt->isArraySliceType()) arrlen = cs->irb.GetArraySliceLength(array); else if(rt->isDynamicArrayType()) arrlen = cs->irb.GetSAALength(array); else iceAssert(0); //* note: 'true' means we're performing a decomposition, so print a more appropriate error message on bounds failure. auto checkf = cgn::glue::array::getBoundsCheckFunction(cs, true); if(checkf) { auto strloc = fir::ConstantCharSlice::get(bind.loc.toString()); cs->irb.Call(checkf, arrlen, numbinds, strloc); } } // # if 0 if(!rhs->islvalue() && rt->isArrayType()) { //* because of the way LLVM is designed, and hence by extension how we are designed, //* fixed-sized arrays are kinda dumb. If we don't have a pointer to the array (for whatever reason???), //* then we can't do a GEP access, and hence can't get a pointer to use for the 'rest' binding. So, //* we error on that case but allow binding the rest. //* theoretically if the compiler is well designed we should never hit this case, but who knows? size_t idx = 0; for(auto& b : bind.inner) { auto v = CGResult(cs->irb.ExtractValue(array, { idx })); cs->generateDecompositionBindings(b, v, false); idx++; } warn(bind.loc, "destructure of array without pointer (shouldn't happen!)"); if(!bind.restName.empty()) error(bind.loc, "could not get pointer to array (of type '%s') to create binding for '...'", rt); } else // #endif { fir::Value* data = 0; if(rt->isArrayType()) data = cs->irb.ConstGEP2(rhs.value, 0, 0); else if(rt->isArraySliceType()) data = cs->irb.GetArraySliceData(array); else if(rt->isDynamicArrayType()) data = cs->irb.GetSAAData(array); else iceAssert(0); size_t idx = 0; for(auto& b : bind.inner) { auto ptr = cs->irb.GetPointer(data, fir::ConstantInt::getNative(idx)); auto v = CGResult(cs->irb.Dereference(ptr)); cs->generateDecompositionBindings(b, v, true); idx++; } if(!bind.restName.empty()) { if(bind.restRef) { auto sty = fir::ArraySliceType::get(rt->getArrayElementType(), shouldSliceBeMutable); auto remaining = cs->irb.Subtract(arrlen, numbinds); auto slice = cs->irb.CreateValue(sty); slice = cs->irb.SetArraySliceData(slice, cs->irb.GetPointer(data, numbinds)); slice = cs->irb.SetArraySliceLength(slice, remaining); handleDefn(cs, bind.restDefn, CGResult(slice)); } else { // always return a dynamic array here. //* note: in order to make our lives somewhat easier, for fixed arrays, we create a fake slice pointing to its data, then we //* call clone on that instead. fir::Value* clonee = 0; if(rt->isArrayType()) { clonee = cs->irb.CreateValue(fir::ArraySliceType::get(rt->getArrayElementType(), shouldSliceBeMutable)); clonee = cs->irb.SetArraySliceData(clonee, data); clonee = cs->irb.SetArraySliceLength(clonee, fir::ConstantInt::getNative(rt->toArrayType()->getArraySize())); } else { clonee = array; } auto clonef = cgn::glue::array::getCloneFunction(cs, clonee->getType()); iceAssert(clonef); auto ret = cs->irb.Call(clonef, clonee, numbinds); handleDefn(cs, bind.restDefn, CGResult(ret)); } } } } } void cgn::CodegenState::generateDecompositionBindings(const DecompMapping& bind, CGResult rhs, bool allowref) { auto rt = rhs.value->getType(); if(!bind.name.empty()) { if(bind.ref && !allowref) error(bind.loc, "cannot bind to value of type '%s' by reference", rt); if(bind.ref) { rhs.value = this->irb.AddressOf(rhs.value, false); } else { // rhs.value = this->irb.Dereference(rhs.value); } handleDefn(this, bind.createdDefn, rhs); } else if(bind.array) { checkArray(this, bind, rhs); } else { checkTuple(this, bind, rhs); } } ================================================ FILE: source/codegen/directives.cpp ================================================ // directives.cpp // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. #include #include "sst.h" #include "codegen.h" #include "platform.h" #include "ir/interp.h" #include "memorypool.h" fir::ConstantValue* magicallyRunExpressionAtCompileTime(cgn::CodegenState* cs, sst::Stmt* stmt, fir::Type* infer, const fir::Name& fname, fir::interp::InterpState* is = 0) { // what we do is to make a new function in IR, set the insertpoint to that, // then run codegen on the expression (so it generates inside), restore the insertpoint, // then run the interpreter on that function (after compiling it), then get the interp::Value // result, make a constantvalue with it auto restore = cs->irb.getCurrentBlock(); bool isExpr = false; fir::Type* retty = 0; if(auto ex = dcast(sst::Expr, stmt); ex) isExpr = true, retty = ex->type; else retty = fir::Type::getVoid(); auto fn = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ }, retty), fir::LinkageType::Internal); iceAssert(fn); iceAssert(stmt); // make the function: { auto entry = cs->irb.addNewBlockInFunction("entry", fn); cs->irb.setCurrentBlock(entry); // we need a block, even though we don't codegen -- this is to handle raii/refcounting things. // stack allocate, so we can get rid of it later. (automatically) auto fakeBlk = sst::Block(Location()); cs->enterBlock(&fakeBlk); fir::Value* ret = 0; if(isExpr) ret = stmt->codegen(cs, infer).value; else stmt->codegen(cs, infer); if(!ret || ret->getType()->isVoidType()) cs->irb.ReturnVoid(); else cs->irb.Return(ret); cs->leaveBlock(); if(restore) cs->irb.setCurrentBlock(restore); } // finalise the global init function if necessary: cs->finishGlobalInitFunction(); // run the function: fir::ConstantValue* ret = 0; { // this unique_ptr handles destructing the temporary interpState when we're done. using unique_ptr_alias = std::unique_ptr>; auto ptr = unique_ptr_alias(); if(!is) { is = new fir::interp::InterpState(cs->module); is->initialise(/* runGlobalInit: */ true); ptr = unique_ptr_alias(is, [](fir::interp::InterpState* is) { is->finalise(); delete is; }); } else { // new strategy: run the initialisers anyway. is->initialise(/* runGlobalInit: */ true); // caller code will finalise. } auto result = is->runFunction(is->compileFunction(fn), { }); if(!retty->isVoidType()) ret = is->unwrapInterpValueIntoConstant(result); } // please get rid of the runner function cs->module->removeFunction(fn); delete fn; return ret; } static size_t runDirectiveId = 0; CGResult sst::RunDirective::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); sst::Stmt* toExec = 0; if(this->insideExpr) toExec = this->insideExpr; else toExec = this->block; auto ret = magicallyRunExpressionAtCompileTime(cs, toExec, infer, fir::Name::obfuscate("run_directive", runDirectiveId++)); return CGResult(ret); } ================================================ FILE: source/codegen/dotop.cpp ================================================ // dotops.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "errors.h" #include "codegen.h" #include "typecheck.h" #include "memorypool.h" static bool isAutoDereferencable(fir::Type* t) { return (t->isStructType() || t->isClassType() || t->isRawUnionType()); } static CGResult getAppropriateValuePointer(cgn::CodegenState* cs, sst::Expr* user, sst::Expr* lhs, fir::Type** baseType) { auto res = lhs->codegen(cs); auto restype = res.value->getType(); fir::Value* retv = 0; if(isAutoDereferencable(restype)) { auto t = res.value->getType(); iceAssert(isAutoDereferencable(t)); retv = res.value; *baseType = restype; } else if(restype->isTupleType()) { retv = res.value; *baseType = restype; } else if(restype->isPointerType() && isAutoDereferencable(restype->getPointerElementType())) { iceAssert(isAutoDereferencable(res.value->getType()->getPointerElementType())); retv = cs->irb.Dereference(res.value); *baseType = restype->getPointerElementType(); } else { error(user, "invalid type '%s' for instance dot op", restype); } return CGResult(retv); } CGResult sst::MethodDotOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); if(auto fc = dcast(sst::FunctionCall, this->call)) { // basically what we need to do is just get the pointer fir::Type* sty = 0; auto res = getAppropriateValuePointer(cs, this, this->lhs, &sty); if(!res->islvalue()) { auto tmplval = cs->irb.CreateLValue(this->lhs->type); cs->irb.Store(res.value, tmplval); res.value = tmplval; res->makeConst(); } // then we insert it as the first argument auto rv = util::pool(this->loc, res.value->getType()->getMutablePointerTo()); rv->rawValue = CGResult(cs->irb.AddressOf(res.value, true)); //! SELF HANDLING (INSERTION) (CODEGEN) fc->arguments.insert(fc->arguments.begin(), FnCallArgument(this->loc, "this", rv, 0)); return fc->codegen(cs); } else if(auto ec = dcast(sst::ExprCall, this->call)) { return ec->codegen(cs); } else { error(this->call, "what?"); } } CGResult sst::FieldDotOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); if(this->isMethodRef) error("method ref not supported"); fir::Type* sty = 0; auto res = getAppropriateValuePointer(cs, this, this->lhs, &sty); // TODO: clean up the code dupe here if(this->isTransparentField) { iceAssert(this->lhs->type->isRawUnionType() || this->lhs->type->isStructType()); if(this->lhs->type->isRawUnionType()) { fir::Value* field = 0; if(res->islvalue()) { field = cs->irb.GetRawUnionFieldByType(res.value, this->type); } else { auto addr = cs->irb.ImmutStackAlloc(this->lhs->type, res.value); field = cs->irb.GetRawUnionFieldByType(addr, this->type); } return CGResult(field); } else { if(res->islvalue()) { // ok, at this point it's just a normal, instance field. return CGResult(cs->irb.StructGEP(res.value, this->indexOfTransparentField)); } else { // use extractvalue. return CGResult(cs->irb.ExtractValue(res.value, { this->indexOfTransparentField })); } } } else { if(this->lhs->type->isRawUnionType()) { fir::Value* field = 0; if(res->islvalue()) { field = cs->irb.GetRawUnionField(res.value, this->rhsIdent); } else { auto addr = cs->irb.ImmutStackAlloc(this->lhs->type, res.value); field = cs->irb.GetRawUnionField(addr, this->rhsIdent); } return CGResult(field); } else { if(res->islvalue()) { // ok, at this point it's just a normal, instance field. return CGResult(cs->irb.GetStructMember(res.value, this->rhsIdent)); } else { // use extractvalue. return CGResult(cs->irb.ExtractValueByName(res.value, this->rhsIdent)); } } } } CGResult sst::TupleDotOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); fir::Type* _sty = 0; auto res = getAppropriateValuePointer(cs, this, this->lhs, &_sty); fir::TupleType* tty = _sty->toTupleType(); iceAssert(tty); // make sure something didn't somehow manage to fuck up -- we should've checked this in the typechecker. iceAssert(this->index < tty->getElementCount()); // ok, if we have a pointer, then return an lvalue // if not, return an rvalue if(res->islvalue()) { return CGResult(cs->irb.StructGEP(res.value, this->index)); } else { return CGResult(cs->irb.ExtractValue(res.value, { this->index })); } } CGResult cgn::CodegenState::getStructFieldImplicitly(std::string name) { fir::Value* self = this->getMethodSelf(); auto ty = self->getType(); auto dothing = [this, name, self](auto sty) -> auto { if(sty->hasElementWithName(name)) { // ok -- return directly from here. fir::Value* ptr = this->irb.GetStructMember(self, name); return CGResult(ptr); } else { error(this->loc(), "type '%s' has no field named '%s'", sty->getTypeName().str(), name); } }; if(ty->isStructType()) return dothing(ty->toStructType()); else if(ty->isClassType()) return dothing(ty->toClassType()); else error(this->loc(), "invalid self type '%s' for field named '%s'", ty, name); } ================================================ FILE: source/codegen/enums.cpp ================================================ // enums.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "sst.h" #include "codegen.h" CGResult sst::EnumDefn::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); iceAssert(this->memberType); // make the runtime array auto values = std::vector(this->cases.size()); auto names = std::vector(this->cases.size()); // ok. for(auto [ n, c ] : this->cases) { // do the case...? should we codegen this shit separately or what auto val = c->codegen(cs).value; iceAssert(val); // ok, then. auto cv = dcast(fir::ConstantValue, val); iceAssert(cv); // values[c->index] = fir::ConstantStruct(cv); names[c->index] = fir::ConstantCharSlice::get(n); } auto et = this->type->toEnumType(); // this is for the actual case { // auto array = fir::ConstantArray::get(fir::ArrayType::get(this->type, values.size()), values); // et->setCaseArray(cs->module->createGlobalVariable(Identifier("_FV_ENUM_ARR_" + this->id.str(), IdKind::Name), // array->getType(), array, true, fir::LinkageType::Internal)); } // this is for the names... I guess? { auto array = fir::ConstantArray::get(fir::ArrayType::get(fir::Type::getCharSlice(false), names.size()), names); et->setNameArray(cs->module->createGlobalVariable(fir::Name::obfuscate("_FV_ENUM_NAME_ARR_", this->id.str()), array->getType(), array, true, fir::LinkageType::Internal)); } return CGResult(0); } CGResult sst::EnumCaseDefn::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); auto base = this->parentEnum->memberType; fir::Value* v = 0; if(this->val) { v = this->val->codegen(cs, base).value; iceAssert(v); if(dcast(fir::ConstantValue, v) == 0) error(this, "enumeration case value ('%s' of type '%s') must be constant", this->id.name, v->getType()); } else { v = fir::ConstantInt::getNative(this->index); } this->value = dcast(fir::ConstantValue, v); { auto ty = this->parentEnum->type; auto ret = fir::ConstantEnumCase::get(ty->toEnumType(), fir::ConstantInt::getNative(this->index), this->value); cs->valueMap[this] = CGResult(ret); } return cs->valueMap[this]; } CGResult sst::EnumDotOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) { error("unsupported"); } ================================================ FILE: source/codegen/function.cpp ================================================ // function.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "defs.h" #include "sst.h" #include "codegen.h" #include "memorypool.h" #include "ir/irbuilder.h" CGResult sst::FunctionDefn::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); if(this->type->containsPlaceholders()) return CGResult(0); std::vector ptypes; for(const auto& p : this->params) ptypes.push_back(p.type); auto ft = fir::FunctionType::get(ptypes, this->returnType); auto ident = this->id; if(this->attrs.hasAny(attr::FN_ENTRYPOINT, attr::NO_MANGLE)) ident = Identifier(this->id.name, IdKind::Name); auto fn = cs->module->getOrCreateFunction(ident.convertToName(), ft, this->visibility == VisibilityLevel::Private ? fir::LinkageType::Internal : fir::LinkageType::External); // manually set the names, I guess { for(size_t i = 0; i < this->params.size(); i++) fn->getArguments()[i]->setName(this->params[i].name); } // special case for functions, to enable recursive calling: // set our cached result *before* we generate our body, in case we contain either // a: a call to ourselves, or // b: a call to someone that call us eventually this->cachedResult = CGResult(fn); auto restore = cs->irb.getCurrentBlock(); defer(cs->irb.setCurrentBlock(restore)); cs->enterFunction(fn); defer(cs->leaveFunction()); auto block = cs->irb.addNewBlockInFunction(this->id.name + "_entry", fn); cs->irb.setCurrentBlock(block); if(this->parentTypeForMethod) cs->enterMethodBody(fn, cs->irb.Dereference(fn->getArguments()[0])); // special thing here: // push a breakable block (ControlFlowPoint) so that a manual 'return' can know how to // do refcounting and deferred things. cs->enterBreakableBody(cgn::ControlFlowPoint(this->body, 0, 0)); { this->body->preBodyCode = [cs, this]() { for(auto arg : this->arguments) arg->codegen(cs); }; this->body->codegen(cs); } cs->leaveBreakableBody(); // note that we *trust* in the typechecker // that all paths return the correct type. if(this->needReturnVoid) cs->irb.ReturnVoid(); if(this->parentTypeForMethod) cs->leaveMethodBody(); if(this->attrs.has(attr::FN_ENTRYPOINT)) { if(cs->entryFunction.first != 0) { SimpleError::make(this->loc, "redefinition of entry function with '@entry'") ->append(SimpleError::make(MsgType::Note, cs->entryFunction.second, "previous entry function marked here:")) ->postAndQuit(); } cs->entryFunction = { fn, this->loc }; } cs->valueMap[this] = CGResult(fn); return CGResult(fn); } CGResult sst::ForeignFuncDefn::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); fir::FunctionType* ft = 0; std::vector ptypes; for(const auto& p : this->params) ptypes.push_back(p.type); if(this->isVarArg) ft = fir::FunctionType::getCVariadicFunc(ptypes, this->returnType); else ft = fir::FunctionType::get(ptypes, this->returnType); auto realId = Identifier(this->realName, IdKind::Name); auto ef = cs->module->getFunction(realId.convertToName()); if(ef && ef->getType() != ft) { error(this, "foreign function '%s' already defined elsewhere (with signature %s); overloading not possible", this->id.str(), ef->getType()); } auto fn = cs->module->getOrCreateFunction(realId.convertToName(), ft, fir::LinkageType::External); if(this->isIntrinsic) fn->setIsIntrinsic(); cs->valueMap[this] = CGResult(fn); return CGResult(fn); } CGResult sst::ArgumentDefn::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); auto fn = cs->getCurrentFunction(); auto arg = cs->irb.CreateLValue(this->type, this->id.name); cs->irb.Store(fn->getArgumentWithName(this->id.name), arg); arg->makeConst(); cs->addRAIIOrRCValueIfNecessary(arg); // ok... cs->valueMap[this] = CGResult(arg); return CGResult(arg); } ================================================ FILE: source/codegen/glue/any.cpp ================================================ // any.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "codegen.h" #include "platform.h" #include "gluecode.h" namespace cgn { namespace glue { namespace any { static void _doRefCount(CodegenState* cs, fir::Function* func, bool decrement) { auto any = func->getArguments()[0]; auto rcp = cs->irb.GetAnyRefCountPointer(any, "rcp"); fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", func); fir::IRBlock* dorc = cs->irb.addNewBlockInFunction("dorc", func); cs->irb.CondBranch(cs->irb.ICmpEQ(rcp, fir::ConstantValue::getZeroValue(fir::Type::getNativeWordPtr())), merge, dorc); cs->irb.setCurrentBlock(dorc); { auto oldrc = cs->irb.ReadPtr(rcp, "oldrc"); auto newrc = cs->irb.Add(oldrc, fir::ConstantInt::getNative(decrement ? -1 : 1)); cs->irb.SetAnyRefCount(any, newrc); #if DEBUG_ANY_REFCOUNTING { std::string x = decrement ? "(decr)" : "(incr)"; cs->printIRDebugMessage("* ANY: " + x + " - new rc of: (rcptr: %p) = %d", { cs->irb.GetAnyRefCountPointer(any), cs->irb.GetAnyRefCount(any) }); } #endif if(decrement) { fir::IRBlock* dofree = cs->irb.addNewBlockInFunction("dofree", func); auto cond = cs->irb.ICmpEQ(newrc, fir::ConstantInt::getNative(0)); // this thing checks for the MSB of the typeid; if it's set, means we used heap memory and so we need to free. cond = cs->irb.BitwiseAND(cond, cs->irb.ICmpGT(cs->irb.BitwiseAND(cs->irb.GetAnyTypeID(any), fir::ConstantInt::getUNative(BUILTIN_ANY_FLAG_MASK)), fir::ConstantInt::getUNative(0))); cs->irb.CondBranch(cond, dofree, merge); cs->irb.setCurrentBlock(dofree); { auto freefn = cs->getOrDeclareLibCFunction(FREE_MEMORY_FUNC); iceAssert(freefn); //* because llvm is a little restrictive wrt. how we can fiddle with types and memory, in //* order to cast the data buffer (which is an array) to a i64*, we first get the array, //* then make a stack alloc, store the array value, use the alloc as an address and cast it //* to i64*, then dereference that to get the actual pointer to the heap memory. // 1. this gets us a memory location we can use. auto _buf = cs->irb.GetAnyData(any, "buf"); auto buf = cs->irb.StackAlloc(_buf->getType()); cs->irb.WritePtr(_buf, buf); // 2. 'buf' is a pointer to the array itself -- we cast it to i64*, so the dereference // gives us the first 8 bytes of the data buffer. buf = cs->irb.PointerTypeCast(buf, fir::Type::getNativeWordPtr()); // 3. this is the dereference. auto ptr = cs->irb.ReadPtr(buf); // 4. the first 8 bytes are actually a pointer to the heap memory. ptr = cs->irb.IntToPointerCast(ptr, fir::Type::getMutInt8Ptr()); cs->irb.Call(freefn, ptr); cs->irb.Call(freefn, cs->irb.PointerTypeCast(cs->irb.GetAnyRefCountPointer(any), fir::Type::getMutInt8Ptr())); #if DEBUG_ANY_ALLOCATION { cs->printIRDebugMessage("* ANY: free(): (ptr: %p / rcp: %p)", { ptr, cs->irb.GetAnyRefCountPointer(any) }); } #endif } } cs->irb.UnCondBranch(merge); } cs->irb.setCurrentBlock(merge); { cs->irb.ReturnVoid(); } } fir::Function* getRefCountIncrementFunction(CodegenState* cs) { auto fname = misc::getIncrRefcount_FName(fir::Type::getAny()); fir::Function* retfn = cs->module->getFunction(fname); if(!retfn) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ fir::Type::getAny() }, fir::Type::getVoid()), fir::LinkageType::Internal); func->setAlwaysInline(); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); _doRefCount(cs, func, false); cs->irb.setCurrentBlock(restore); retfn = func; } iceAssert(retfn); return retfn; } fir::Function* getRefCountDecrementFunction(CodegenState* cs) { auto fname = misc::getDecrRefcount_FName(fir::Type::getAny()); fir::Function* retfn = cs->module->getFunction(fname); if(!retfn) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ fir::Type::getAny() }, fir::Type::getVoid()), fir::LinkageType::Internal); func->setAlwaysInline(); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); _doRefCount(cs, func, true); cs->irb.setCurrentBlock(restore); retfn = func; } iceAssert(retfn); return retfn; } fir::Function* generateCreateAnyWithValueFunction(CodegenState* cs, fir::Type* type) { auto fname = misc::getCreateAnyOf_FName(type); fir::Function* retfn = cs->module->getFunction(fname); if(!retfn) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ type }, fir::Type::getAny()), fir::LinkageType::Internal); func->setAlwaysInline(); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); auto any = cs->irb.CreateValue(fir::Type::getAny()); auto dataarrty = fir::ArrayType::get(fir::Type::getInt8(), BUILTIN_ANY_DATA_BYTECOUNT); // make the refcount pointer. auto rcp = cs->irb.PointerTypeCast(cs->irb.Call(cs->getOrDeclareLibCFunction(ALLOCATE_MEMORY_FUNC), fir::ConstantInt::getNative(REFCOUNT_SIZE)), fir::Type::getNativeWordPtr()); any = cs->irb.SetAnyRefCountPointer(any, rcp); cs->irb.SetAnyRefCount(any, fir::ConstantInt::getNative(1)); size_t tid = type->getID(); if(auto typesz = fir::getSizeOfType(type); typesz > BUILTIN_ANY_DATA_BYTECOUNT) { tid |= BUILTIN_ANY_FLAG_MASK; auto ptr = cs->irb.PointerTypeCast(cs->irb.Call(cs->getOrDeclareLibCFunction(ALLOCATE_MEMORY_FUNC), fir::ConstantInt::getNative(typesz)), type->getMutablePointerTo()); #if DEBUG_ANY_ALLOCATION { cs->printIRDebugMessage("* ANY: alloc(): (id: %lu, ptr: %p / rcp: %p)", { fir::ConstantInt::getUNative(tid), ptr, rcp }); } #endif cs->irb.WritePtr(func->getArguments()[0], ptr); ptr = cs->irb.PointerToIntCast(ptr, fir::Type::getNativeWord()); // now, we make a fake data, and then store it. auto arrptr = cs->irb.StackAlloc(dataarrty); auto fakeptr = cs->irb.PointerTypeCast(arrptr, fir::Type::getNativeWordPtr()->getMutablePointerVersion()); cs->irb.WritePtr(ptr, fakeptr); auto arr = cs->irb.ReadPtr(arrptr); any = cs->irb.SetAnyData(any, arr); } else { auto arrptr = cs->irb.StackAlloc(dataarrty); auto fakeptr = cs->irb.PointerTypeCast(arrptr, type->getMutablePointerTo()); cs->irb.WritePtr(func->getArguments()[0], fakeptr); auto arr = cs->irb.ReadPtr(arrptr); any = cs->irb.SetAnyData(any, arr); } any = cs->irb.SetAnyTypeID(any, fir::ConstantInt::getUNative(tid)); cs->irb.Return(any); cs->irb.setCurrentBlock(restore); retfn = func; } iceAssert(retfn); return retfn; } fir::Function* generateGetValueFromAnyFunction(CodegenState* cs, fir::Type* type) { auto fname = misc::getGetValueFromAny_FName(type); fir::Function* retfn = cs->module->getFunction(fname); if(!retfn) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ fir::Type::getAny() }, type), fir::LinkageType::Internal); func->setAlwaysInline(); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); auto any = func->getArguments()[0]; auto dataarrty = fir::ArrayType::get(fir::Type::getInt8(), BUILTIN_ANY_DATA_BYTECOUNT); auto tid = cs->irb.BitwiseAND(cs->irb.GetAnyTypeID(any), fir::ConstantInt::getUNative(~BUILTIN_ANY_FLAG_MASK)); fir::IRBlock* invalid = cs->irb.addNewBlockInFunction("invalid", cs->irb.getCurrentFunction()); fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", cs->irb.getCurrentFunction()); auto valid = cs->irb.ICmpEQ(tid, fir::ConstantInt::getUNative(type->getID())); cs->irb.CondBranch(valid, merge, invalid); cs->irb.setCurrentBlock(invalid); { printRuntimeError(cs, fir::ConstantCharSlice::get(cs->loc().toString()), "invalid unwrap of 'any' with type id '%ld' into type '%s' (with id '%ld')", { tid, cs->module->createGlobalString(type->str()), fir::ConstantInt::getUNative(type->getID()) } ); } cs->irb.setCurrentBlock(merge); { if(fir::getSizeOfType(type) > BUILTIN_ANY_DATA_BYTECOUNT) { // same as above, but in reverse. auto arrptr = cs->irb.StackAlloc(dataarrty); cs->irb.WritePtr(cs->irb.GetAnyData(any), arrptr); // cast the array* into a type**, so when we dereference it, we get the first 8 bytes interpreted as a type*. // we then just load and return that. auto fakeptr = cs->irb.PointerTypeCast(arrptr, type->getMutablePointerTo()->getMutablePointerTo()); auto typeptr = cs->irb.ReadPtr(fakeptr); cs->irb.Return(cs->irb.ReadPtr(typeptr)); } else { auto arrptr = cs->irb.StackAlloc(dataarrty); cs->irb.WritePtr(cs->irb.GetAnyData(any), arrptr); // same as above but we skip a load. auto fakeptr = cs->irb.PointerTypeCast(arrptr, type->getMutablePointerTo()); auto ret = cs->irb.ReadPtr(fakeptr); cs->irb.Return(ret); } } cs->irb.setCurrentBlock(restore); retfn = func; } iceAssert(retfn); return retfn; } } } } ================================================ FILE: source/codegen/glue/arrays.cpp ================================================ // arrays.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "codegen.h" #include "platform.h" #include "gluecode.h" namespace cgn { namespace glue { namespace array { fir::Function* getBoundsCheckFunction(CodegenState* cs, bool isPerformingDecomposition) { return saa_common::generateBoundsCheckFunction(cs, /* isString: */false, isPerformingDecomposition); } fir::Function* getCloneFunction(CodegenState* cs, fir::Type* arrtype) { return saa_common::generateCloneFunction(cs, arrtype); } fir::Function* getReserveExtraFunction(CodegenState* cs, fir::DynamicArrayType* arrtype) { return saa_common::generateReserveExtraFunction(cs, arrtype); } fir::Function* getReserveAtLeastFunction(CodegenState* cs, fir::DynamicArrayType* arrtype) { return saa_common::generateReserveAtLeastFunction(cs, arrtype); } fir::Function* getAppendFunction(CodegenState* cs, fir::DynamicArrayType* arrtype) { return saa_common::generateAppendFunction(cs, arrtype); } fir::Function* getElementAppendFunction(CodegenState* cs, fir::DynamicArrayType* arrtype) { return saa_common::generateElementAppendFunction(cs, arrtype); } fir::Function* getCallClassConstructorOnElementsFunction(CodegenState* cs, fir::ClassType* cls, sst::FunctionDefn* constr, const std::vector& args) { iceAssert(cls); auto fname = misc::getCallClassConstructor_FName(cls); fir::Function* fn = cs->module->getFunction(fname); if(!fn) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ cls->getPointerTo(), fir::Type::getNativeWord() }, fir::Type::getVoid()), fir::LinkageType::Internal); func->setAlwaysInline(); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); // ok: the real difference with the one below is that we need to call the constructor function on every element. fir::Value* arrdata = func->getArguments()[0]; fir::Value* len = func->getArguments()[1]; fir::IRBlock* check = cs->irb.addNewBlockInFunction("check", func); fir::IRBlock* body = cs->irb.addNewBlockInFunction("body", func); fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", func); auto ctrptr = cs->irb.StackAlloc(fir::Type::getNativeWord()); // already set to 0 internally cs->irb.UnCondBranch(check); cs->irb.setCurrentBlock(check); { auto cond = cs->irb.ICmpLT(cs->irb.ReadPtr(ctrptr), len); cs->irb.CondBranch(cond, body, merge); } cs->irb.setCurrentBlock(body); { auto ctr = cs->irb.ReadPtr(ctrptr); auto ptr = cs->irb.GetPointer(arrdata, ctr); auto val = cs->constructClassWithArguments(cls, constr, args); // TODO: this is a bit dubious?? cs->irb.WritePtr(val, ptr); cs->irb.WritePtr(cs->irb.Add(ctr, fir::ConstantInt::getNative(1)), ctrptr); cs->irb.UnCondBranch(check); } cs->irb.setCurrentBlock(merge); cs->irb.ReturnVoid(); cs->irb.setCurrentBlock(restore); fn = func; } return fn; } fir::Function* getSetElementsToValueFunction(CodegenState* cs, fir::Type* elmType) { iceAssert(elmType); auto fname = misc::getSetElements_FName(elmType); fir::Function* fn = cs->module->getFunction(fname); if(!fn) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ elmType->getMutablePointerTo(), fir::Type::getNativeWord(), elmType }, fir::Type::getVoid()), fir::LinkageType::Internal); func->setAlwaysInline(); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); fir::Value* arrdata = func->getArguments()[0]; fir::Value* len = func->getArguments()[1]; fir::Value* value = func->getArguments()[2]; iceAssert(value); fir::IRBlock* check = cs->irb.addNewBlockInFunction("check", func); fir::IRBlock* body = cs->irb.addNewBlockInFunction("body", func); fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", func); auto ctrptr = cs->irb.StackAlloc(fir::Type::getNativeWord()); cs->irb.UnCondBranch(check); cs->irb.setCurrentBlock(check); { auto cond = cs->irb.ICmpLT(cs->irb.ReadPtr(ctrptr), len); cs->irb.CondBranch(cond, body, merge); } cs->irb.setCurrentBlock(body); { auto ctr = cs->irb.ReadPtr(ctrptr); auto ptr = cs->irb.GetPointer(arrdata, ctr); cs->autoAssignRefCountedValue(ptr, value, true); cs->irb.WritePtr(cs->irb.Add(ctr, fir::ConstantInt::getNative(1)), ctrptr); cs->irb.UnCondBranch(check); } cs->irb.setCurrentBlock(merge); cs->irb.ReturnVoid(); cs->irb.setCurrentBlock(restore); fn = func; } return fn; } fir::Function* getSetElementsToDefaultValueFunction(CodegenState* cs, fir::Type* elmType) { iceAssert(elmType); auto fname = misc::getSetElementsDefault_FName(elmType); fir::Function* fn = cs->module->getFunction(fname); if(!fn) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ elmType->getMutablePointerTo(), fir::Type::getNativeWord() }, fir::Type::getVoid()), fir::LinkageType::Internal); func->setAlwaysInline(); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); fir::Value* value = 0; if(elmType->isClassType()) value = cs->irb.CreateValue(elmType); else value = cs->getDefaultValue(elmType); iceAssert(value); auto setfn = getSetElementsToValueFunction(cs, elmType); iceAssert(setfn); cs->irb.Call(setfn, func->getArguments()[0], func->getArguments()[1], value); cs->irb.ReturnVoid(); cs->irb.setCurrentBlock(restore); fn = func; } return fn; } static void _compareFunctionUsingBuiltinCompare(CodegenState* cs, fir::Type* arrtype, fir::Function* func, fir::Value* arg1, fir::Value* arg2) { // ok, ez. fir::Value* zeroval = fir::ConstantInt::getNative(0); fir::Value* oneval = fir::ConstantInt::getNative(1); fir::IRBlock* cond = cs->irb.addNewBlockInFunction("cond", func); fir::IRBlock* body = cs->irb.addNewBlockInFunction("body", func); fir::IRBlock* incr = cs->irb.addNewBlockInFunction("incr", func); fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", func); fir::Value* ptr1 = 0; fir::Value* ptr2 = 0; if(arrtype->isDynamicArrayType()) { ptr1 = cs->irb.GetSAAData(arg1); ptr2 = cs->irb.GetSAAData(arg2); } else if(arrtype->isArraySliceType()) { ptr1 = cs->irb.GetArraySliceData(arg1); ptr2 = cs->irb.GetArraySliceData(arg2); } else if(arrtype->isArrayType()) { ptr1 = cs->irb.ConstGEP2(arg1, 0, 0); ptr2 = cs->irb.ConstGEP2(arg2, 0, 0); } else { error("invalid type '%s'", arrtype); } fir::Value* len1 = 0; fir::Value* len2 = 0; if(arrtype->isDynamicArrayType()) { len1 = cs->irb.GetSAALength(arg1); len2 = cs->irb.GetSAALength(arg2); } else if(arrtype->isArraySliceType()) { len1 = cs->irb.GetArraySliceLength(arg1); len2 = cs->irb.GetArraySliceLength(arg2); } else if(arrtype->isArrayType()) { len1 = fir::ConstantInt::getNative(arrtype->toArrayType()->getArraySize()); len2 = fir::ConstantInt::getNative(arrtype->toArrayType()->getArraySize()); } else { error("invalid type '%s'", arrtype); } // we compare to this to break fir::Value* counter = cs->irb.StackAlloc(fir::Type::getNativeWord()); cs->irb.WritePtr(zeroval, counter); fir::Value* res = cs->irb.StackAlloc(fir::Type::getNativeWord()); cs->irb.WritePtr(zeroval, res); cs->irb.UnCondBranch(cond); cs->irb.setCurrentBlock(cond); { fir::IRBlock* retlt = cs->irb.addNewBlockInFunction("retlt", func); fir::IRBlock* reteq = cs->irb.addNewBlockInFunction("reteq", func); fir::IRBlock* retgt = cs->irb.addNewBlockInFunction("retgt", func); fir::IRBlock* tmp1 = cs->irb.addNewBlockInFunction("tmp1", func); fir::IRBlock* tmp2 = cs->irb.addNewBlockInFunction("tmp2", func); // if we got here, the arrays were equal *up to this point* // if ptr1 exceeds or ptr2 exceeds, return len1 - len2 fir::Value* t1 = cs->irb.ICmpEQ(cs->irb.ReadPtr(counter), len1); fir::Value* t2 = cs->irb.ICmpEQ(cs->irb.ReadPtr(counter), len2); // if t1 is over, goto tmp1, if not goto t2 cs->irb.CondBranch(t1, tmp1, tmp2); cs->irb.setCurrentBlock(tmp1); { // t1 is over // check if t2 is over // if so, return 0 (b == a) // if not, return -1 (b > a) cs->irb.CondBranch(t2, reteq, retlt); } cs->irb.setCurrentBlock(tmp2); { // t1 is not over // check if t2 is over // if so, return 1 (a > b) // if not, goto body cs->irb.CondBranch(t2, retgt, body); } cs->irb.setCurrentBlock(retlt); cs->irb.Return(fir::ConstantInt::getNative(-1)); cs->irb.setCurrentBlock(reteq); cs->irb.Return(fir::ConstantInt::getNative(0)); cs->irb.setCurrentBlock(retgt); cs->irb.Return(fir::ConstantInt::getNative(+1)); } cs->irb.setCurrentBlock(body); { fir::Value* v1 = cs->irb.ReadPtr(cs->irb.GetPointer(ptr1, cs->irb.ReadPtr(counter))); fir::Value* v2 = cs->irb.ReadPtr(cs->irb.GetPointer(ptr2, cs->irb.ReadPtr(counter))); fir::Value* c = cs->performBinaryOperation(cs->loc(), { cs->loc(), v1 }, { cs->loc(), v2 }, "==").value; // c is a bool, because it's very generic in nature // so we just take !c and convert to i64 to get our result. // if c == true, then lhs == rhs, and so we should have 0. c = cs->irb.LogicalNot(c); c = cs->irb.IntSizeCast(c, fir::Type::getNativeWord()); cs->irb.WritePtr(c, res); // compare to 0. fir::Value* cmpres = cs->irb.ICmpEQ(cs->irb.ReadPtr(res), zeroval); // if equal, go to incr, if not return directly cs->irb.CondBranch(cmpres, incr, merge); } cs->irb.setCurrentBlock(incr); { cs->irb.WritePtr(cs->irb.Add(cs->irb.ReadPtr(counter), oneval), counter); cs->irb.UnCondBranch(cond); } cs->irb.setCurrentBlock(merge); { // load and return cs->irb.Return(cs->irb.ReadPtr(res)); } } static void _compareFunctionUsingOperatorFunction(CodegenState* cs, fir::Type* arrtype, fir::Function* curfunc, fir::Value* arg1, fir::Value* arg2, fir::Function* opf) { error("notsup"); } fir::Function* getCompareFunction(CodegenState* cs, fir::Type* arrtype, fir::Function* opf) { iceAssert(arrtype); auto fname = misc::getCompare_FName(arrtype); fir::Function* cmpf = cs->module->getFunction(fname); if(!cmpf) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ arrtype, arrtype }, fir::Type::getNativeWord()), fir::LinkageType::Internal); func->setAlwaysInline(); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); fir::Value* s1 = func->getArguments()[0]; fir::Value* s2 = func->getArguments()[1]; { // check our situation. if(opf == 0) { _compareFunctionUsingBuiltinCompare(cs, arrtype, func, s1, s2); } else { _compareFunctionUsingOperatorFunction(cs, arrtype, func, s1, s2, opf); } // functions above do their own return } cs->irb.setCurrentBlock(restore); cmpf = func; } iceAssert(cmpf); return cmpf; } static fir::Function* makeRecursiveRefCountingFunction(CodegenState* cs, fir::DynamicArrayType* arrtype, bool incr) { auto fname = misc::getRecursiveRefcount_FName(arrtype, incr); fir::Function* retf = cs->module->getFunction(fname); if(!retf) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ arrtype }, fir::Type::getVoid()), fir::LinkageType::Internal); func->setAlwaysInline(); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); fir::Value* arr = func->getArguments()[0]; auto ptr = cs->irb.GetSAAData(arr); auto len = cs->irb.GetSAALength(arr); auto cap = cs->irb.GetSAACapacity(arr); { auto elmtype = arrtype->getElementType(); // here we check whether we actually have a refcount pointer. If we don't, then we're a literal, and there's no need to change // the refcount anyway. auto prevblk = cs->irb.getCurrentBlock(); auto dorc = cs->irb.addNewBlockInFunction("dorc", cs->irb.getCurrentFunction()); auto dontrc = cs->irb.addNewBlockInFunction("dontrcliteral", cs->irb.getCurrentFunction()); { auto rcp = cs->irb.GetSAARefCountPointer(arr); auto cond = cs->irb.ICmpNEQ(cs->irb.PointerToIntCast(rcp, fir::Type::getNativeWord()), fir::ConstantInt::getNative(0)); cs->irb.CondBranch(cond, dorc, dontrc); } fir::Value* therefc = 0; cs->irb.setCurrentBlock(dorc); { therefc = cs->irb.GetSAARefCount(arr); fir::Value* newrc = 0; if(incr) newrc = cs->irb.Add(therefc, fir::ConstantInt::getNative(1)); else newrc = cs->irb.Subtract(therefc, fir::ConstantInt::getNative(1)); // update it. therefc = newrc; cs->irb.SetSAARefCount(arr, newrc); cs->irb.UnCondBranch(dontrc); } cs->irb.setCurrentBlock(dontrc); #if DEBUG_ARRAY_REFCOUNTING { std::string x = incr ? "(incr)" : "(decr)"; cs->printIRDebugMessage("* ARRAY: " + x + " - new rc of: (ptr: %p, len: %ld, cap: %ld) = %d", { cs->irb.GetSAAData(arr), cs->irb.GetSAALength(arr), cs->irb.GetSAACapacity(arr), cs->irb.GetSAARefCount(arr) }); } #endif // ok. if we're incrementing, then we're done -- but if we're decrementing, we may need to free the memory. if(!incr) { fir::IRBlock* dealloc = cs->irb.addNewBlockInFunction("dealloc", func); fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", func); auto zv = fir::ConstantInt::getNative(0); //! NOTE: what we want to happen here is for us to free the memory, but only if refcnt == 0 && capacity >= 0 //* so our condition is (REFCOUNT == 0) & (CAP >= 0) auto refc = cs->irb.CreatePHINode(fir::Type::getNativeWord()); refc->addIncoming(therefc, dorc); refc->addIncoming(fir::ConstantInt::getNative(-1), prevblk); auto dofree = cs->irb.BitwiseAND(cs->irb.ICmpEQ(refc, zv), cs->irb.ICmpGEQ(cap, zv)); cs->irb.CondBranch(dofree, dealloc, merge); cs->irb.setCurrentBlock(dealloc); { auto memptr = cs->irb.PointerTypeCast(ptr, fir::Type::getMutInt8Ptr()); auto freefn = cs->getOrDeclareLibCFunction(FREE_MEMORY_FUNC); iceAssert(freefn); // only when we free, do we loop through our array and decrement its refcount. if(fir::isRefCountedType(elmtype)) { auto ctrp = cs->irb.StackAlloc(fir::Type::getNativeWord()); cs->irb.WritePtr(zv, ctrp); cs->createWhileLoop([cs, ctrp, len](auto pass, auto fail) { auto cond = cs->irb.ICmpLT(cs->irb.ReadPtr(ctrp), len); cs->irb.CondBranch(cond, pass, fail); }, [cs, ctrp, ptr]() { auto ctr = cs->irb.ReadPtr(ctrp); auto p = cs->irb.GetPointer(ptr, ctr); cs->decrementRefCount(cs->irb.ReadPtr(p)); cs->irb.WritePtr(cs->irb.Add(ctr, fir::ConstantInt::getNative(1)), ctrp); }); } cs->irb.Call(freefn, memptr); cs->irb.Call(freefn, cs->irb.PointerTypeCast(cs->irb.GetSAARefCountPointer(arr), fir::Type::getMutInt8Ptr())); #if DEBUG_ARRAY_ALLOCATION { cs->printIRDebugMessage("* ARRAY: free(): (ptr: %p / rcp: %p)", { memptr, cs->irb.GetSAARefCountPointer(arr) }); } #endif cs->irb.UnCondBranch(merge); } cs->irb.setCurrentBlock(merge); } } cs->irb.ReturnVoid(); cs->irb.setCurrentBlock(restore); retf = func; } iceAssert(retf); return retf; } static fir::Function* _getDoRefCountFunctionForDynamicArray(CodegenState* cs, fir::DynamicArrayType* arrtype, bool increment) { auto fname = (increment ? misc::getLoopIncrRefcount_FName(arrtype) : misc::getLoopDecrRefcount_FName(arrtype)); fir::Function* cmpf = cs->module->getFunction(fname); if(!cmpf) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ arrtype }, arrtype), fir::LinkageType::Internal); func->setAlwaysInline(); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); fir::Value* arr = func->getArguments()[0]; auto fn = makeRecursiveRefCountingFunction(cs, arr->getType()->toDynamicArrayType(), increment); iceAssert(fn); cs->irb.Call(fn, arr); cs->irb.Return(arr); cs->irb.setCurrentBlock(restore); cmpf = func; } iceAssert(cmpf); return cmpf; } static fir::Function* _getDoRefCountFunctionForArray(CodegenState* cs, fir::ArrayType* arrtype, bool incr) { error("NO!"); } fir::Function* getIncrementArrayRefCountFunction(CodegenState* cs, fir::Type* arrtype) { if(arrtype->isDynamicArrayType()) return _getDoRefCountFunctionForDynamicArray(cs, arrtype->toDynamicArrayType(), true); else return _getDoRefCountFunctionForArray(cs, arrtype->toArrayType(), true); } fir::Function* getDecrementArrayRefCountFunction(CodegenState* cs, fir::Type* arrtype) { if(arrtype->isDynamicArrayType()) return _getDoRefCountFunctionForDynamicArray(cs, arrtype->toDynamicArrayType(), false); else return _getDoRefCountFunctionForArray(cs, arrtype->toArrayType(), false); } fir::Function* getConstructFromTwoFunction(CodegenState* cs, fir::DynamicArrayType* arrtype) { return saa_common::generateConstructFromTwoFunction(cs, arrtype); } fir::Function* getPopElementFromBackFunction(CodegenState* cs, fir::Type* arrtype) { iceAssert(arrtype); iceAssert(arrtype->isDynamicArrayType() || arrtype->isArraySliceType()); auto fname = misc::getPopBack_FName(arrtype); fir::Function* fn = cs->module->getFunction(fname); if(!fn) { bool isslice = arrtype->isArraySliceType(); auto restore = cs->irb.getCurrentBlock(); auto retTy = fir::TupleType::get({ arrtype, arrtype->getArrayElementType() }); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ arrtype, fir::Type::getCharSlice(false) }, retTy), fir::LinkageType::Internal); func->setAlwaysInline(); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); fir::Value* arr = func->getArguments()[0]; fir::Value* loc = func->getArguments()[1]; fir::Value* origlen = (isslice ? cs->irb.GetArraySliceLength(arr) : cs->irb.GetSAALength(arr)); fir::IRBlock* fail = cs->irb.addNewBlockInFunction("fail", func); fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", func); auto cond = cs->irb.ICmpLT(origlen, fir::ConstantInt::getNative(1)); cs->irb.CondBranch(cond, fail, merge); cs->irb.setCurrentBlock(fail); { printRuntimeError(cs, loc, "calling pop() on an empty array\n", { }); } cs->irb.setCurrentBlock(merge); { auto newlen = cs->irb.Subtract(origlen, fir::ConstantInt::getNative(1)); fir::Value* ret = 0; // first, load the last value if(isslice) { auto ptr = cs->irb.GetArraySliceData(arr); auto val = cs->irb.ReadPtr(cs->irb.GetPointer(ptr, newlen)); auto newarr = cs->irb.SetArraySliceLength(arr, newlen); ret = cs->irb.CreateValue(retTy); ret = cs->irb.InsertValue(ret, { 0 }, newarr); ret = cs->irb.InsertValue(ret, { 1 }, val); } else { auto ptr = cs->irb.GetSAAData(arr); auto val = cs->irb.ReadPtr(cs->irb.GetPointer(ptr, newlen)); auto newarr = cs->irb.SetSAALength(arr, newlen); ret = cs->irb.CreateValue(retTy); ret = cs->irb.InsertValue(ret, { 0 }, newarr); ret = cs->irb.InsertValue(ret, { 1 }, val); } iceAssert(ret); cs->irb.Return(ret); } cs->irb.setCurrentBlock(restore); fn = func; } return fn; } } } } ================================================ FILE: source/codegen/glue/misc.cpp ================================================ // misc.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "codegen.h" #include "platform.h" #include "gluecode.h" #include "frontend.h" namespace cgn { namespace glue { void printRuntimeError(cgn::CodegenState* cs, fir::Value* pos, const std::string& message, const std::vector& args) { //! on windows, apparently fprintf doesn't like to work. //! so we just use normal printf. if(!frontend::getIsNoRuntimeErrorStrings()) { iceAssert(pos->getType()->isCharSliceType()); fir::Value* fmtstr = cs->module->createGlobalString(("\nRuntime error at %s:\n" + message + "\n").c_str()); fir::Value* posstr = cs->irb.GetArraySliceData(pos); std::vector as = { fmtstr, posstr }; as.insert(as.end(), args.begin(), args.end()); cs->irb.Call(cs->getOrDeclareLibCFunction("printf"), as); } cs->irb.Call(cs->getOrDeclareLibCFunction("abort")); cs->irb.Unreachable(); } namespace misc { fir::Function* getMallocWrapperFunction(CodegenState* cs) { auto fname = getMallocWrapper_FName(); fir::Function* fn = cs->module->getFunction(fname); if(!fn) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ fir::Type::getNativeWord(), fir::Type::getCharSlice(false) }, fir::Type::getMutInt8Ptr()), fir::LinkageType::Internal); func->setAlwaysInline(); auto sz = func->getArguments()[0]; auto locstr = func->getArguments()[1]; auto entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); // do the alloc. auto mallocf = cs->getOrDeclareLibCFunction(ALLOCATE_MEMORY_FUNC); iceAssert(mallocf); auto mem = cs->irb.Call(mallocf, sz); auto cond = cs->irb.ICmpEQ(mem, fir::ConstantValue::getZeroValue(fir::Type::getInt8Ptr())); auto alloc_succ = cs->irb.addNewBlockAfter("success", cs->irb.getCurrentBlock()); auto alloc_fail = cs->irb.addNewBlockAfter("failure", cs->irb.getCurrentBlock()); cs->irb.CondBranch(cond, alloc_fail, alloc_succ); cs->irb.setCurrentBlock(alloc_succ); { cs->irb.Return(mem); } cs->irb.setCurrentBlock(alloc_fail); { printRuntimeError(cs, locstr, "allocation failed (returned null) (tried to allocate %d bytes)", { sz }); // it emits an unreachable for us. } fn = func; cs->irb.setCurrentBlock(restore); } iceAssert(fn); return fn; } fir::Function* getRangeSanityCheckFunction(CodegenState* cs) { if(frontend::getIsNoRuntimeChecks()) return 0; auto fname = getRangeSanityCheck_FName(); fir::Function* fn = cs->module->getFunction(fname); if(!fn) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ fir::Type::getRange(), fir::Type::getCharSlice(false) }, fir::Type::getVoid()), fir::LinkageType::Internal); func->setAlwaysInline(); /* Valid scenarios: 1. start <= end, step > 0 2. start >= end, step < 0 */ auto entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); auto check = cs->irb.addNewBlockAfter("check", cs->irb.getCurrentBlock()); auto checkstepneg = cs->irb.addNewBlockAfter("checkstepneg", cs->irb.getCurrentBlock()); auto checksteppos = cs->irb.addNewBlockAfter("checksteppos", cs->irb.getCurrentBlock()); auto stepnotneg = cs->irb.addNewBlockAfter("fail_stepnotneg", cs->irb.getCurrentBlock()); auto stepnotpos = cs->irb.addNewBlockAfter("fail_stepnotpos", cs->irb.getCurrentBlock()); auto stepzero = cs->irb.addNewBlockAfter("fail_stepzero", cs->irb.getCurrentBlock()); auto merge = cs->irb.addNewBlockAfter("merge", cs->irb.getCurrentBlock()); auto lower = cs->irb.GetRangeLower(func->getArguments()[0]); auto upper = cs->irb.GetRangeUpper(func->getArguments()[0]); auto step = cs->irb.GetRangeStep(func->getArguments()[0]); auto zero = fir::ConstantInt::getNative(0); // first of all check if step is zero. { auto cond = cs->irb.ICmpEQ(step, zero); cs->irb.CondBranch(cond, stepzero, check); } // first, check if start <= end. cs->irb.setCurrentBlock(check); { auto cond = cs->irb.ICmpLEQ(lower, upper); // if start < end, check step > 0. else check step < 0. cs->irb.CondBranch(cond, checksteppos, checkstepneg); } cs->irb.setCurrentBlock(checksteppos); { auto cond = cs->irb.ICmpGT(step, zero); cs->irb.CondBranch(cond, merge, stepnotpos); } cs->irb.setCurrentBlock(checkstepneg); { auto cond = cs->irb.ICmpLT(step, zero); cs->irb.CondBranch(cond, merge, stepnotneg); } // ok, now the failure messages. { cs->irb.setCurrentBlock(stepzero); { printRuntimeError(cs, func->getArguments()[1], "range step had value of zero\n", { }); } cs->irb.setCurrentBlock(stepnotpos); { printRuntimeError(cs, func->getArguments()[1], "range had negative step value ('%ld'); invalid when start < end\n", { step }); } cs->irb.setCurrentBlock(stepnotneg); { printRuntimeError(cs, func->getArguments()[1], "range had positive step value ('%ld'); invalid when start > end\n", { step }); } } cs->irb.setCurrentBlock(merge); cs->irb.ReturnVoid(); fn = func; cs->irb.setCurrentBlock(restore); } iceAssert(fn); return fn; } using Idt = fir::Name; Idt getOI(const std::string& name, fir::Type* t = 0) { if(t) return fir::Name::obfuscate(name, t->encodedStr()); else return fir::Name::obfuscate(name); } Idt getCompare_FName(fir::Type* t) { return getOI("compare", t); } Idt getSetElements_FName(fir::Type* t) { return getOI("setelements", t); } Idt getCallClassConstructor_FName(fir::Type* t) { return getOI("callclassinit", t); } Idt getSetElementsDefault_FName(fir::Type* t) { return getOI("setelementsdefault", t); } Idt getClone_FName(fir::Type* t) { return getOI("clone", t); } Idt getAppend_FName(fir::Type* t) { return getOI("append", t); } Idt getPopBack_FName(fir::Type* t) { return getOI("popback", t); } Idt getMakeFromOne_FName(fir::Type* t) { return getOI("makefromone", t); } Idt getMakeFromTwo_FName(fir::Type* t) { return getOI("makefromtwo", t); } Idt getReserveExtra_FName(fir::Type* t) { return getOI("reserveextra", t); } Idt getAppendElement_FName(fir::Type* t) { return getOI("appendelement", t); } Idt getReserveEnough_FName(fir::Type* t) { return getOI("reservesufficient", t); } Idt getRecursiveRefcount_FName(fir::Type* t, bool incr) { return getOI(strprintf("rrc_%s", incr ? "incr" : "decr"), t); } Idt getIncrRefcount_FName(fir::Type* t) { return getOI("incr_rc", t); } Idt getDecrRefcount_FName(fir::Type* t) { return getOI("decr_rc", t); } Idt getLoopIncrRefcount_FName(fir::Type* t) { return getOI("loop_incr_rc", t); } Idt getLoopDecrRefcount_FName(fir::Type* t) { return getOI("loop_decr_rc", t); } Idt getCreateAnyOf_FName(fir::Type* t) { return getOI("create_any_of", t); } Idt getGetValueFromAny_FName(fir::Type* t) { return getOI("get_value_from_any", t); } Idt getUtf8Length_FName() { return getOI("utf8_length"); } Idt getRangeSanityCheck_FName() { return getOI("range_sanity"); } Idt getMallocWrapper_FName() { return getOI("malloc_wrapper"); } Idt getBoundsCheck_FName() { return getOI("boundscheck"); } Idt getDecompBoundsCheck_FName() { return getOI("boundscheck_decomp"); } } } } ================================================ FILE: source/codegen/glue/saa_common.cpp ================================================ // saa_common.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "codegen.h" #include "platform.h" #include "gluecode.h" #include "frontend.h" // namespace cgn::glue::saa_common namespace cgn { namespace glue { namespace saa_common { static inline bool isSAA(fir::Type* t) { return t->isStringType() || t->isDynamicArrayType(); } static inline fir::Type* getSAAElm(fir::Type* t) { iceAssert(isSAA(t)); return (t->isStringType() ? fir::Type::getInt8() : t->getArrayElementType()); } static inline fir::Type* getSAASlice(fir::Type* t, bool mut = true) { iceAssert(isSAA(t)); return fir::ArraySliceType::get(getSAAElm(t), mut); } static inline fir::ConstantInt* getCI(int64_t i) { return fir::ConstantInt::getNative(i); } static fir::Value* castRawBufToElmPtr(CodegenState* cs, fir::Type* saa, fir::Value* buf) { auto ptrty = getSAAElm(saa)->getMutablePointerTo(); if(buf->getType()->isPointerType()) return cs->irb.PointerTypeCast(buf, ptrty); else return cs->irb.IntToPointerCast(buf, ptrty); } static fir::Function* generateIncrementArrayRefCountInLoopFunction(CodegenState* cs, fir::Type* elm) { iceAssert(fir::isRefCountedType(elm)); auto fname = misc::getLoopIncrRefcount_FName(elm); fir::Function* retfn = cs->module->getFunction(fname); if(!retfn) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ elm->getPointerTo(), fir::Type::getNativeWord() }, fir::Type::getVoid()), fir::LinkageType::Internal); func->setAlwaysInline(); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); fir::IRBlock* cond = cs->irb.addNewBlockInFunction("loopCond", func); fir::IRBlock* body = cs->irb.addNewBlockInFunction("loopBody", func); fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", func); fir::Value* ctrPtr = cs->irb.StackAlloc(fir::Type::getNativeWord()); fir::Value* s2ptr = func->getArguments()[0]; fir::Value* s2len = func->getArguments()[1]; cs->irb.UnCondBranch(cond); cs->irb.setCurrentBlock(cond); { // check the condition fir::Value* ctr = cs->irb.ReadPtr(ctrPtr); fir::Value* res = cs->irb.ICmpLT(ctr, s2len); cs->irb.CondBranch(res, body, merge); } cs->irb.setCurrentBlock(body); { // increment refcount fir::Value* val = cs->irb.ReadPtr(cs->irb.GetPointer(s2ptr, cs->irb.ReadPtr(ctrPtr))); cs->incrementRefCount(val); // increment counter cs->irb.WritePtr(cs->irb.Add(fir::ConstantInt::getNative(1), cs->irb.ReadPtr(ctrPtr)), ctrPtr); cs->irb.UnCondBranch(cond); } cs->irb.setCurrentBlock(merge); cs->irb.ReturnVoid(); cs->irb.setCurrentBlock(restore); retfn = func; } iceAssert(retfn); return retfn; } fir::Value* makeNewRefCountPointer(CodegenState* cs, fir::Value* rc) { iceAssert(rc->getType()->isIntegerType() && "not integer type"); auto rcp = cs->irb.Call(cs->getOrDeclareLibCFunction(ALLOCATE_MEMORY_FUNC), getCI(REFCOUNT_SIZE)); rcp = cs->irb.PointerTypeCast(rcp, fir::Type::getNativeWordPtr()->getMutablePointerVersion()); cs->irb.WritePtr(rc, rcp); return cs->irb.PointerTypeCast(rcp, fir::Type::getNativeWordPtr()); } fir::Value* initSAAWithRefCount(CodegenState* cs, fir::Value* saa, fir::Value* rc) { iceAssert(isSAA(saa->getType()) && "not saa type"); iceAssert(rc->getType()->isIntegerType() && "not integer type"); auto rcp = makeNewRefCountPointer(cs, rc); return cs->irb.SetSAARefCountPointer(saa, rcp); } /* * NOTE * since we're changing strings and dynamic arrays to behave much the same way, why not just collapse the runtime gluecode as much as possible. we're going with the { ptr, len, cap, rcp } structure for both types, and so we can do a lot of things commonly. one thing is that we still want null terminators on strings, so that's just a couple of if-checks sprinkled around -- nothing too obnoxious. */ static void _callCloneFunctionInLoop(CodegenState* cs, fir::Function* curfunc, fir::Function* fn, fir::Value* ptr, fir::Value* len, fir::Value* newptr, fir::Value* startIndex) { fir::IRBlock* loopcond = cs->irb.addNewBlockInFunction("loopcond", curfunc); fir::IRBlock* loopbody = cs->irb.addNewBlockInFunction("loopbody", curfunc); fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", curfunc); fir::Value* counter = cs->irb.StackAlloc(fir::Type::getNativeWord()); cs->irb.WritePtr(startIndex, counter); cs->irb.UnCondBranch(loopcond); cs->irb.setCurrentBlock(loopcond); { fir::Value* res = cs->irb.ICmpEQ(cs->irb.ReadPtr(counter), len); cs->irb.CondBranch(res, merge, loopbody); } cs->irb.setCurrentBlock(loopbody); { // make clone fir::Value* origElm = cs->irb.GetPointer(ptr, cs->irb.ReadPtr(counter)); fir::Value* clone = 0; //* note: the '0' argument specifies the offset to clone from -- since want the whole thing, the offset is 0. auto elm = cs->irb.ReadPtr(origElm); clone = cs->irb.Call(fn, isSAA(elm->getType()) ? cs->irb.CreateSliceFromSAA(elm, false) : elm, fir::ConstantInt::getNative(0)); // store clone fir::Value* newElm = cs->irb.GetPointer(newptr, cs->irb.ReadPtr(counter)); cs->irb.WritePtr(clone, newElm); // increment counter cs->irb.WritePtr(cs->irb.Add(cs->irb.ReadPtr(counter), fir::ConstantInt::getNative(1)), counter); cs->irb.UnCondBranch(loopcond); } cs->irb.setCurrentBlock(merge); } static void _handleCallingAppropriateCloneFunction(CodegenState* cs, fir::Function* func, fir::Type* elmType, fir::Value* oldptr, fir::Value* newptr, fir::Value* oldlen, fir::Value* bytecount, fir::Value* startIndex) { if(elmType->isPrimitiveType() || elmType->isCharType() || elmType->isEnumType()) { fir::Function* memcpyf = cs->module->getIntrinsicFunction("memmove"); cs->irb.Call(memcpyf, { newptr, cs->irb.PointerTypeCast(cs->irb.GetPointer(oldptr, startIndex), fir::Type::getMutInt8Ptr()), bytecount, fir::ConstantBool::get(false) }); #if DEBUG_ARRAY_ALLOCATION | DEBUG_STRING_ALLOCATION { cs->printIRDebugMessage("* SAACOM: clone(): (oldptr: %p, oldlen: %d), (newptr: %p, bytecount: %d, index: %d)", { oldptr, oldlen, newptr, bytecount, startIndex }); } #endif } else if(elmType->isDynamicArrayType()) { // yo dawg i heard you like arrays... fir::Function* clonef = generateCloneFunction(cs, elmType); iceAssert(clonef); // loop fir::Value* cloneptr = cs->irb.PointerTypeCast(newptr, elmType->getMutablePointerTo()); _callCloneFunctionInLoop(cs, func, clonef, oldptr, oldlen, cloneptr, startIndex); } else if(elmType->isArraySliceType()) { // yo dawg i heard you like arrays... fir::Function* clonef = generateCloneFunction(cs, elmType); iceAssert(clonef); // loop fir::Value* cloneptr = cs->irb.PointerTypeCast(newptr, elmType->getMutablePointerTo()); _callCloneFunctionInLoop(cs, func, clonef, oldptr, oldlen, cloneptr, startIndex); } else if(elmType->isStringType()) { fir::Function* clonef = glue::string::getCloneFunction(cs); iceAssert(clonef); // loop fir::Value* cloneptr = cs->irb.PointerTypeCast(newptr, elmType->getMutablePointerTo()); _callCloneFunctionInLoop(cs, func, clonef, oldptr, oldlen, cloneptr, startIndex); } else if(elmType->isStructType() || elmType->isClassType() || elmType->isTupleType() || elmType->isArrayType()) { // todo: call copy constructors and stuff fir::Function* memcpyf = cs->module->getIntrinsicFunction("memmove"); cs->irb.Call(memcpyf, { newptr, cs->irb.PointerTypeCast(cs->irb.GetPointer(oldptr, startIndex), fir::Type::getMutInt8Ptr()), bytecount, fir::ConstantBool::get(false) }); } else { error("unsupported element type '%s' for array clone", elmType); } } fir::Function* generateCloneFunction(CodegenState* cs, fir::Type* _saa) { auto fname = misc::getClone_FName(_saa); iceAssert(isSAA(_saa) || _saa->isArraySliceType()); auto slicetype = (isSAA(_saa) ? getSAASlice(_saa, false) : fir::ArraySliceType::get(_saa->getArrayElementType(), false)); iceAssert(slicetype->isArraySliceType()); bool isArray = !_saa->isStringType(); fir::Type* outtype = (isSAA(_saa) ? _saa : fir::DynamicArrayType::get(slicetype->getArrayElementType())); fir::Function* retfn = cs->module->getFunction(fname); if(!retfn) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ slicetype, fir::Type::getNativeWord() }, outtype), fir::LinkageType::Internal); func->setAlwaysInline(); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); auto s1 = func->getArguments()[0]; auto cloneofs = func->getArguments()[1]; auto lhsbuf = cs->irb.GetArraySliceData(s1, "lhsbuf"); fir::IRBlock* isnull = cs->irb.addNewBlockInFunction("isnull", func); fir::IRBlock* notnull = cs->irb.addNewBlockInFunction("notnull", func); // if it's null we just fuck off now. cs->irb.CondBranch(cs->irb.ICmpEQ(lhsbuf, fir::ConstantValue::getZeroValue(slicetype->getArrayElementType()->getPointerTo())), isnull, notnull); cs->irb.setCurrentBlock(notnull); { auto lhslen = cs->irb.Subtract(cs->irb.GetArraySliceLength(s1, "l1"), cloneofs, "lhslen"); auto newcap = cs->irb.Call(cs->module->getIntrinsicFunction("roundup_pow2"), lhslen, "newcap"); auto lhsbytecount = cs->irb.Multiply(lhslen, cs->irb.Sizeof(slicetype->getArrayElementType()), "lhsbytecount"); auto newbytecount = cs->irb.Multiply(newcap, cs->irb.Sizeof(slicetype->getArrayElementType()), "newbytecount"); fir::Value* newbuf = cs->irb.Call(cgn::glue::misc::getMallocWrapperFunction(cs), !isArray ? cs->irb.Add(newbytecount, getCI(1)) : newbytecount, fir::ConstantCharSlice::get("(no location)"), "buf"); { // fir::Function* memcpyf = cs->module->getIntrinsicFunction("memmove"); // cs->irb.Call(memcpyf, { buf, castRawBufToElmPtr(cs, saa, lhsbuf), lhsbytecount, // fir::ConstantInt::getInt32(0), fir::ConstantBool::get(false) }); _handleCallingAppropriateCloneFunction(cs, func, slicetype->getArrayElementType(), lhsbuf, newbuf, lhslen, lhsbytecount, cloneofs); // null terminator if(!isArray) cs->irb.WritePtr(fir::ConstantInt::getInt8(0), cs->irb.GetPointer(newbuf, lhsbytecount)); } { auto ret = cs->irb.CreateValue(outtype); ret = cs->irb.SetSAAData(ret, castRawBufToElmPtr(cs, outtype, newbuf)); ret = cs->irb.SetSAALength(ret, lhslen); //? vv for the null terminator ret = cs->irb.SetSAACapacity(ret, !isArray ? cs->irb.Subtract(newcap, getCI(1)) : newcap); ret = initSAAWithRefCount(cs, ret, getCI(1)); cs->irb.Return(ret); } } cs->irb.setCurrentBlock(isnull); { auto ret = cs->irb.CreateValue(outtype); ret = cs->irb.SetSAAData(ret, castRawBufToElmPtr(cs, outtype, getCI(0))); ret = cs->irb.SetSAALength(ret, getCI(0)); ret = cs->irb.SetSAACapacity(ret, getCI(0)); ret = initSAAWithRefCount(cs, ret, getCI(1)); cs->irb.Return(ret); } retfn = func; cs->irb.setCurrentBlock(restore); } iceAssert(retfn); return retfn; } fir::Function* generateAppropriateAppendFunction(CodegenState* cs, fir::Type* saa, fir::Type* appendee) { iceAssert(isSAA(saa)); if(appendee == getSAAElm(saa)) return generateElementAppendFunction(cs, saa); else if(zfu::match(appendee, getSAASlice(saa), getSAASlice(saa, false), saa)) return generateAppendFunction(cs, saa); else error(cs->loc(), "cannot append '%s' to '%s'", appendee, saa); } fir::Function* generateAppendFunction(CodegenState* cs, fir::Type* saa) { auto fname = misc::getAppend_FName(saa); iceAssert(isSAA(saa)); fir::Function* retfn = cs->module->getFunction(fname); if(!retfn) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ saa, getSAASlice(saa, false) }, saa), fir::LinkageType::Internal); func->setAlwaysInline(); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); fir::Value* lhs = func->getArguments()[0]; fir::Value* rhs = func->getArguments()[1]; auto lhslen = cs->irb.GetSAALength(lhs, "lhslen"); auto rhsbuf = cs->irb.GetArraySliceData(rhs, "rhsbuf"); auto rhslen = cs->irb.GetArraySliceLength(rhs, "rhslen"); auto rhsbytecount = cs->irb.Multiply(rhslen, cs->irb.Sizeof(rhs->getType()->getArrayElementType()), "rhsbytecount"); // this handles the null case as well. lhs = cs->irb.Call(generateReserveAtLeastFunction(cs, saa), lhs, cs->irb.Add(lhslen, rhslen)); auto lhsbuf = cs->irb.GetSAAData(lhs, "lhsbuf"); // do a copy over the rhs. { fir::Function* memcpyf = cs->module->getIntrinsicFunction("memmove"); cs->irb.Call(memcpyf, { cs->irb.PointerTypeCast(cs->irb.GetPointer(lhsbuf, lhslen), fir::Type::getMutInt8Ptr()), cs->irb.PointerTypeCast(rhsbuf, fir::Type::getMutInt8Ptr()), rhsbytecount, fir::ConstantBool::get(false) }); // null terminator if(saa->isStringType()) { cs->irb.WritePtr(fir::ConstantInt::getInt8(0), cs->irb.PointerTypeCast(cs->irb.GetPointer(lhsbuf, cs->irb.Add(lhslen, rhslen)), fir::Type::getMutInt8Ptr())); } } lhs = cs->irb.SetSAALength(lhs, cs->irb.Add(lhslen, rhslen)); // handle refcounting if(fir::isRefCountedType(getSAAElm(saa))) { auto incrfn = generateIncrementArrayRefCountInLoopFunction(cs, getSAAElm(saa)); iceAssert(incrfn); cs->irb.Call(incrfn, rhsbuf, rhslen); } cs->irb.Return(lhs); cs->irb.setCurrentBlock(restore); retfn = func; } iceAssert(retfn); return retfn; } fir::Function* generateElementAppendFunction(CodegenState* cs, fir::Type* saa) { auto fname = misc::getAppendElement_FName(saa); iceAssert(isSAA(saa)); fir::Function* retfn = cs->module->getFunction(fname); if(!retfn) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ saa, getSAAElm(saa) }, saa), fir::LinkageType::Internal); func->setAlwaysInline(); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); fir::Value* lhs = func->getArguments()[0]; fir::Value* rhs = func->getArguments()[1]; auto rhsp = cs->irb.ImmutStackAlloc(getSAAElm(saa), rhs, "rhsptr"); auto rhsslice = cs->irb.CreateValue(getSAASlice(saa), "rhsslice"); rhsslice = cs->irb.SetArraySliceData(rhsslice, cs->irb.PointerTypeCast(rhsp, rhsp->getType()->getMutablePointerVersion())); rhsslice = cs->irb.SetArraySliceLength(rhsslice, getCI(1)); auto appf = generateAppendFunction(cs, saa); iceAssert(appf); auto ret = cs->irb.Call(appf, lhs, rhsslice); cs->irb.Return(ret); cs->irb.setCurrentBlock(restore); retfn = func; } iceAssert(retfn); return retfn; } fir::Function* generateConstructFromTwoFunction(CodegenState* cs, fir::Type* saa) { auto fname = misc::getMakeFromTwo_FName(saa); iceAssert(isSAA(saa)); fir::Function* retfn = cs->module->getFunction(fname); if(!retfn) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ getSAASlice(saa, false), getSAASlice(saa, false) }, saa), fir::LinkageType::Internal); func->setAlwaysInline(); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); fir::Value* lhs = func->getArguments()[0]; fir::Value* rhs = func->getArguments()[1]; auto lhslen = cs->irb.GetArraySliceLength(lhs, "lhslen"); auto rhslen = cs->irb.GetArraySliceLength(rhs, "rhslen"); auto lhsbuf = cs->irb.GetArraySliceData(lhs, "lhsbuf"); auto rhsbuf = cs->irb.GetArraySliceData(rhs, "rhsbuf"); // step 1 -- make a null of the SAA auto ret = cs->irb.CreateValue(saa); ret = cs->irb.SetSAAData(ret, castRawBufToElmPtr(cs, saa, getCI(0))); ret = cs->irb.SetSAALength(ret, getCI(0)); ret = cs->irb.SetSAACapacity(ret, getCI(0)); //? vv we count on the 'reserveAtLeast' function to init our refcount ret = cs->irb.SetSAARefCountPointer(ret, fir::ConstantValue::getZeroValue(fir::Type::getNativeWordPtr())); ret = cs->irb.Call(generateReserveAtLeastFunction(cs, saa), ret, cs->irb.Add(cs->irb.Add(lhslen, rhslen), saa->isStringType() ? getCI(1) : getCI(0))); #if DEBUG_ARRAY_ALLOCATION | DEBUG_STRING_ALLOCATION { cs->printIRDebugMessage("* SAACOM: construct2(): (ptr: %p, len: %d) + (ptr: %p, len: %d) = %p", { lhsbuf, lhslen, rhsbuf, rhslen, cs->irb.GetSAAData(ret) }); } #endif auto buf = cs->irb.GetSAAData(ret, "buf"); { fir::Function* memcpyf = cs->module->getIntrinsicFunction("memmove"); auto rawbuf = cs->irb.PointerTypeCast(buf, fir::Type::getMutInt8Ptr(), "rawbuf"); auto rawlhsbuf = cs->irb.PointerTypeCast(lhsbuf, fir::Type::getMutInt8Ptr(), "rawlhsbuf"); auto rawrhsbuf = cs->irb.PointerTypeCast(rhsbuf, fir::Type::getMutInt8Ptr(), "rawrhsbuf"); auto lhsbytecount = cs->irb.Multiply(lhslen, cs->irb.Sizeof(getSAAElm(saa)), "lhsbytecount"); auto rhsbytecount = cs->irb.Multiply(rhslen, cs->irb.Sizeof(getSAAElm(saa)), "rhsbytecount"); cs->irb.Call(memcpyf, { rawbuf, rawlhsbuf, lhsbytecount, fir::ConstantBool::get(false) }); cs->irb.Call(memcpyf, { cs->irb.GetPointer(rawbuf, lhsbytecount), rawrhsbuf, rhsbytecount, fir::ConstantBool::get(false) }); // if it's a string, again, null terminator. if(saa->isStringType()) { cs->irb.WritePtr(fir::ConstantInt::getInt8(0), cs->irb.GetPointer(rawbuf, cs->irb.Add(lhsbytecount, rhsbytecount))); } else if(fir::isRefCountedType(getSAAElm(saa))) { auto incrfn = generateIncrementArrayRefCountInLoopFunction(cs, getSAAElm(saa)); iceAssert(incrfn); cs->irb.Call(incrfn, lhsbuf, lhslen); cs->irb.Call(incrfn, rhsbuf, rhslen); } ret = cs->irb.SetSAALength(ret, cs->irb.Add(lhslen, rhslen)); cs->irb.Return(ret); } cs->irb.setCurrentBlock(restore); retfn = func; } iceAssert(retfn); return retfn; } fir::Function* generateConstructWithElementFunction(CodegenState* cs, fir::Type* saa) { auto fname = misc::getMakeFromOne_FName(saa); iceAssert(isSAA(saa)); fir::Function* retfn = cs->module->getFunction(fname); if(!retfn) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ getSAASlice(saa), getSAAElm(saa) }, saa), fir::LinkageType::Internal); func->setAlwaysInline(); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); fir::Value* lhs = func->getArguments()[0]; fir::Value* rhs = func->getArguments()[1]; auto rhsslice = cs->irb.CreateValue(getSAASlice(saa, /* mut: */ false), "rhsslice"); rhsslice = cs->irb.SetArraySliceData(rhsslice, cs->irb.ImmutStackAlloc(getSAAElm(saa), rhs, "rhsptr")); rhsslice = cs->irb.SetArraySliceLength(rhsslice, getCI(1)); auto appf = generateConstructFromTwoFunction(cs, saa); iceAssert(appf); auto ret = cs->irb.Call(appf, lhs, rhsslice); cs->irb.Return(ret); cs->irb.setCurrentBlock(restore); retfn = func; } iceAssert(retfn); return retfn; } // TODO: this shit is bloody unmaintainable fir::Function* generateReserveAtLeastFunction(CodegenState* cs, fir::Type* saa) { auto fname = misc::getReserveEnough_FName(saa); iceAssert(isSAA(saa)); fir::Function* retfn = cs->module->getFunction(fname); if(!retfn) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ saa, fir::Type::getNativeWord() }, saa), fir::LinkageType::Internal); func->setAlwaysInline(); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); auto s1 = func->getArguments()[0]; auto minsz = func->getArguments()[1]; auto oldlen = cs->irb.GetSAALength(s1, "oldlen"); auto oldcap = cs->irb.GetSAACapacity(s1, "oldcap"); fir::IRBlock* nullrc = cs->irb.addNewBlockInFunction("nullrc", func); fir::IRBlock* notnullrc = cs->irb.addNewBlockInFunction("notnullrc", func); fir::IRBlock* mergerc = cs->irb.addNewBlockInFunction("mergerc", func); auto oldrcp = cs->irb.GetSAARefCountPointer(s1, "oldrcp"); cs->irb.CondBranch(cs->irb.ICmpEQ(oldrcp, cs->irb.IntToPointerCast(getCI(0), fir::Type::getNativeWordPtr())), nullrc, notnullrc); //? these phi nodes are for the refcount pointer of the thing we will eventually return. fir::Value* nullphi = 0; fir::Value* notnullphi = 0; cs->irb.setCurrentBlock(nullrc); { nullphi = makeNewRefCountPointer(cs, getCI(1)); cs->irb.UnCondBranch(mergerc); } cs->irb.setCurrentBlock(notnullrc); { notnullphi = cs->irb.GetSAARefCountPointer(s1, "oldref"); cs->irb.UnCondBranch(mergerc); } cs->irb.setCurrentBlock(mergerc); { auto rcptr = cs->irb.CreatePHINode(fir::Type::getNativeWordPtr()); rcptr->addIncoming(nullphi, nullrc); rcptr->addIncoming(notnullphi, notnullrc); fir::IRBlock* returnUntouched = cs->irb.addNewBlockInFunction("noExpansion", func); fir::IRBlock* doExpansion = cs->irb.addNewBlockInFunction("expand", func); cs->irb.CondBranch(cs->irb.ICmpLEQ(minsz, oldcap), returnUntouched, doExpansion); cs->irb.setCurrentBlock(doExpansion); { auto newlen = cs->irb.Divide(cs->irb.Multiply(minsz, getCI(3)), getCI(2), "mul1.5"); // call realloc. handles the null case as well, which is nice. const auto oldbuf = cs->irb.PointerTypeCast(cs->irb.GetSAAData(s1), fir::Type::getMutInt8Ptr(), "oldbuf"); auto newbytecount = cs->irb.Multiply(newlen, cs->irb.Sizeof(getSAAElm(saa)), "newbytecount"); if(saa->isStringType()) newbytecount = cs->irb.Add(newbytecount, getCI(1)); // if the capacity was negative, then the buffer points to constant memory that did not come from the heap!! // so, we cannot call realloc with oldbuf, and call it with NULL instead. also for strings, capacity of 0 is empty // so we do the same dealio. auto isfake = cs->irb.ICmpLEQ(oldcap, getCI(0)); auto origbuf = cs->irb.Select(isfake, fir::ConstantValue::getZeroValue(fir::Type::getMutInt8Ptr()), oldbuf); auto _newbuf = cs->irb.Call(cs->getOrDeclareLibCFunction(REALLOCATE_MEMORY_FUNC), origbuf, newbytecount, "newbuf"); auto newbuf = castRawBufToElmPtr(cs, saa, _newbuf); // again with the NULL thingy: now we need to (possibly) copy the data from the old buffer to the new buffer // bopian need some branching here. { auto needcopy = cs->irb.addNewBlockInFunction("copyold", func); auto nocopy = cs->irb.addNewBlockInFunction("nocopyold", func); cs->irb.CondBranch(isfake, needcopy, nocopy); cs->irb.setCurrentBlock(needcopy); { cs->irb.Call(cs->module->getIntrinsicFunction("memmove"), _newbuf, oldbuf, cs->irb.Multiply(oldlen, cs->irb.Sizeof(getSAAElm(saa))), /* isVolatile: */ fir::ConstantBool::get(false)); cs->irb.UnCondBranch(nocopy); } cs->irb.setCurrentBlock(nocopy); } // null terminator if(saa->isStringType()) cs->irb.WritePtr(fir::ConstantInt::getInt8(0), cs->irb.GetPointer(newbuf, cs->irb.Subtract(newbytecount, getCI(1)))); auto ret = cs->irb.CreateValue(saa); ret = cs->irb.SetSAAData(ret, newbuf); ret = cs->irb.SetSAALength(ret, oldlen); ret = cs->irb.SetSAACapacity(ret, newlen); ret = cs->irb.SetSAARefCountPointer(ret, rcptr); #if DEBUG_ARRAY_ALLOCATION | DEBUG_STRING_ALLOCATION { cs->printIRDebugMessage("* SAACOM: realloc(): (ptr: %p, cap: %d / rcp: %p)", { newbuf, newlen, cs->irb.GetSAARefCountPointer(ret) }); } #endif cs->irb.Return(ret); } cs->irb.setCurrentBlock(returnUntouched); { // as the name implies, do nothing. cs->irb.Return(s1); } } cs->irb.setCurrentBlock(restore); retfn = func; } iceAssert(retfn); return retfn; } fir::Function* generateReserveExtraFunction(CodegenState* cs, fir::Type* saa) { // we can just do this in terms of reserveAtLeast. auto fname = misc::getReserveExtra_FName(saa); iceAssert(isSAA(saa)); fir::Function* retfn = cs->module->getFunction(fname); if(!retfn) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ saa, fir::Type::getNativeWord() }, saa), fir::LinkageType::Internal); func->setAlwaysInline(); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); auto s1 = func->getArguments()[0]; auto extrasz = func->getArguments()[1]; auto minsz = cs->irb.Add(cs->irb.GetSAACapacity(s1), extrasz); auto ret = cs->irb.Call(generateReserveAtLeastFunction(cs, saa), s1, minsz); cs->irb.Return(ret); cs->irb.setCurrentBlock(restore); retfn = func; } iceAssert(retfn); return retfn; } fir::Function* generateBoundsCheckFunction(CodegenState* cs, bool isString, bool isDecomp) { if(frontend::getIsNoRuntimeChecks()) return 0; auto fname = (isDecomp ? misc::getDecompBoundsCheck_FName() : misc::getBoundsCheck_FName()); fir::Function* retfn = cs->module->getFunction(fname); if(!retfn) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ fir::Type::getNativeWord(), fir::Type::getNativeWord(), fir::Type::getCharSlice(false) }, fir::Type::getVoid()), fir::LinkageType::Internal); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); fir::IRBlock* failb = cs->irb.addNewBlockInFunction("fail", func); fir::IRBlock* checkneg = cs->irb.addNewBlockInFunction("checkneg", func); fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", func); cs->irb.setCurrentBlock(entry); fir::Value* max = func->getArguments()[0]; fir::Value* ind = func->getArguments()[1]; fir::Value* res = 0; // if we're decomposing, it's length vs length, so compare strictly greater. if(isDecomp) res = cs->irb.ICmpGT(ind, max); else res = cs->irb.ICmpGEQ(ind, max); cs->irb.CondBranch(res, failb, checkneg); cs->irb.setCurrentBlock(failb); { if(isDecomp) { printRuntimeError(cs, func->getArguments()[2], "index '%ld' out of bounds for " + std::string(isString ? "string" : "array") + " of length %ld\n", { ind, max }); } else { printRuntimeError(cs, func->getArguments()[2], "binding of '%ld' " + std::string(isString ? "chars" : "elements") + " out of bounds for string of length %ld\n", { ind, max }); } } cs->irb.setCurrentBlock(checkneg); { fir::Value* res = cs->irb.ICmpLT(ind, fir::ConstantInt::getNative(0)); cs->irb.CondBranch(res, failb, merge); } cs->irb.setCurrentBlock(merge); { cs->irb.ReturnVoid(); } retfn = func; cs->irb.setCurrentBlock(restore); } iceAssert(retfn); return retfn; } } } } ================================================ FILE: source/codegen/glue/strings.cpp ================================================ // strings.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "codegen.h" #include "platform.h" #include "gluecode.h" // generate runtime glue code namespace cgn { namespace glue { namespace string { fir::Function* getCloneFunction(CodegenState* cs) { return saa_common::generateCloneFunction(cs, fir::Type::getString()); } fir::Function* getAppendFunction(CodegenState* cs) { return saa_common::generateAppendFunction(cs, fir::Type::getString()); } fir::Function* getCharAppendFunction(CodegenState* cs) { return saa_common::generateElementAppendFunction(cs, fir::Type::getString()); } fir::Function* getConstructFromTwoFunction(CodegenState* cs) { return saa_common::generateConstructFromTwoFunction(cs, fir::Type::getString()); } fir::Function* getConstructWithCharFunction(CodegenState* cs) { return saa_common::generateConstructWithElementFunction(cs, fir::Type::getString()); } fir::Function* getBoundsCheckFunction(CodegenState* cs, bool isDecomp) { return saa_common::generateBoundsCheckFunction(cs, /* isString: */ true, isDecomp); } fir::Function* getCompareFunction(CodegenState* cs) { auto fname = misc::getCompare_FName(fir::Type::getString()); fir::Function* cmpf = cs->module->getFunction(fname); if(!cmpf) { // great. auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ fir::Type::getString(), fir::Type::getString() }, fir::Type::getNativeWord()), fir::LinkageType::Internal); func->setAlwaysInline(); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); fir::Value* s1 = func->getArguments()[0]; fir::Value* s2 = func->getArguments()[1]; /* int strcmp(const char* s1, const char* s2) { while(*s1 && (*s1 == *s2)) s1++, s2++; return *(const unsigned char*) s1 - *(const unsigned char*) s2; } */ { fir::Value* str1p = cs->irb.StackAlloc(fir::Type::getMutInt8Ptr()); cs->irb.WritePtr(cs->irb.GetSAAData(s1, "s1"), str1p); fir::Value* str2p = cs->irb.StackAlloc(fir::Type::getMutInt8Ptr()); cs->irb.WritePtr(cs->irb.GetSAAData(s2, "s2"), str2p); fir::IRBlock* loopcond = cs->irb.addNewBlockInFunction("cond1", func); fir::IRBlock* loopincr = cs->irb.addNewBlockInFunction("loopincr", func); fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", func); cs->irb.UnCondBranch(loopcond); cs->irb.setCurrentBlock(loopcond); { fir::IRBlock* cond2 = cs->irb.addNewBlockInFunction("cond2", func); fir::Value* str1 = cs->irb.ReadPtr(str1p); fir::Value* str2 = cs->irb.ReadPtr(str2p); // make sure ptr1 is not null fir::Value* cnd = cs->irb.ICmpNEQ(cs->irb.ReadPtr(str1), fir::ConstantInt::getInt8(0)); cs->irb.CondBranch(cnd, cond2, merge); cs->irb.setCurrentBlock(cond2); { // check that they are equal fir::Value* iseq = cs->irb.ICmpEQ(cs->irb.ReadPtr(str1), cs->irb.ReadPtr(str2)); cs->irb.CondBranch(iseq, loopincr, merge); } cs->irb.setCurrentBlock(loopincr); { // increment str1 and str2 fir::Value* v1 = cs->irb.GetPointer(str1, fir::ConstantInt::getNative(1)); fir::Value* v2 = cs->irb.GetPointer(str2, fir::ConstantInt::getNative(1)); cs->irb.WritePtr(v1, str1p); cs->irb.WritePtr(v2, str2p); cs->irb.UnCondBranch(loopcond); } } cs->irb.setCurrentBlock(merge); fir::Value* ret = cs->irb.Subtract(cs->irb.ReadPtr(cs->irb.ReadPtr(str1p)), cs->irb.ReadPtr(cs->irb.ReadPtr(str2p))); ret = cs->irb.IntSizeCast(ret, func->getReturnType()); cs->irb.Return(ret); } cmpf = func; cs->irb.setCurrentBlock(restore); } iceAssert(cmpf); return cmpf; } static void _doRefCount(CodegenState* cs, fir::Function* func, bool decrement) { auto str = func->getArguments()[0]; auto rcp = cs->irb.GetSAARefCountPointer(str, "rcp"); fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", func); fir::IRBlock* dorc = cs->irb.addNewBlockInFunction("dorc", func); cs->irb.CondBranch(cs->irb.ICmpEQ(rcp, fir::ConstantValue::getZeroValue(fir::Type::getNativeWordPtr())), merge, dorc); cs->irb.setCurrentBlock(dorc); { auto oldrc = cs->irb.ReadPtr(rcp, "oldrc"); auto newrc = cs->irb.Add(oldrc, fir::ConstantInt::getNative(decrement ? -1 : 1)); cs->irb.SetSAARefCount(str, newrc); #if DEBUG_STRING_REFCOUNTING { std::string x = decrement ? "(decr)" : "(incr)"; cs->printIRDebugMessage("* STRING: " + x + " - new rc of: (ptr: %p, len: %ld, cap: %ld) = %d", { cs->irb.GetSAAData(str), cs->irb.GetSAALength(str), cs->irb.GetSAACapacity(str), cs->irb.GetSAARefCount(str) }); } #endif if(decrement) { fir::IRBlock* dofree = cs->irb.addNewBlockInFunction("dofree", func); cs->irb.CondBranch(cs->irb.ICmpEQ(newrc, fir::ConstantInt::getNative(0)), dofree, merge); cs->irb.setCurrentBlock(dofree); { auto freefn = cs->getOrDeclareLibCFunction(FREE_MEMORY_FUNC); iceAssert(freefn); auto buf = cs->irb.GetSAAData(str, "buf"); buf = cs->irb.PointerTypeCast(buf, fir::Type::getMutInt8Ptr()); cs->irb.Call(freefn, buf); cs->irb.Call(freefn, cs->irb.PointerTypeCast(cs->irb.GetSAARefCountPointer(str), fir::Type::getMutInt8Ptr())); #if DEBUG_STRING_ALLOCATION { cs->printIRDebugMessage("* STRING: free(): (ptr: %p / rcp: %p)", { buf, cs->irb.GetSAARefCountPointer(str) }); } #endif } } cs->irb.UnCondBranch(merge); } cs->irb.setCurrentBlock(merge); { cs->irb.ReturnVoid(); } } fir::Function* getRefCountIncrementFunction(CodegenState* cs) { auto fname = misc::getIncrRefcount_FName(fir::Type::getString()); fir::Function* retfn = cs->module->getFunction(fname); if(!retfn) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ fir::Type::getString() }, fir::Type::getVoid()), fir::LinkageType::Internal); func->setAlwaysInline(); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); _doRefCount(cs, func, false); cs->irb.setCurrentBlock(restore); retfn = func; } iceAssert(retfn); return retfn; } fir::Function* getRefCountDecrementFunction(CodegenState* cs) { auto fname = misc::getDecrRefcount_FName(fir::Type::getString()); fir::Function* retfn = cs->module->getFunction(fname); if(!retfn) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ fir::Type::getString() }, fir::Type::getVoid()), fir::LinkageType::Internal); func->setAlwaysInline(); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); _doRefCount(cs, func, true); cs->irb.setCurrentBlock(restore); retfn = func; } iceAssert(retfn); return retfn; } fir::Function* getUnicodeLengthFunction(CodegenState* cs) { auto fname = misc::getUtf8Length_FName(); fir::Function* lenf = cs->module->getFunction(fname); if(!lenf) { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fname, fir::FunctionType::get({ fir::Type::getInt8Ptr() }, fir::Type::getNativeWord()), fir::LinkageType::Internal); func->setAlwaysInline(); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); fir::Value* _ptr = func->getArguments()[0]; iceAssert(_ptr); fir::Value* ptrp = cs->irb.StackAlloc(fir::Type::getInt8Ptr()); cs->irb.WritePtr(_ptr, ptrp); /* public fn Utf8Length(_text: i8*) -> i64 { var len = 0 var text = _text while *text != 0 { if (*text & 0xC0) != 0x80 { len += 1 } text = text + 1 } return len } */ auto i0 = fir::ConstantInt::getNative(0); auto i1 = fir::ConstantInt::getNative(1); auto c0 = fir::ConstantInt::getInt8(0); fir::Value* lenp = cs->irb.StackAlloc(fir::Type::getNativeWord()); cs->irb.WritePtr(i0, lenp); fir::IRBlock* cond = cs->irb.addNewBlockInFunction("cond", func); fir::IRBlock* body = cs->irb.addNewBlockInFunction("body", func); fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", func); fir::Value* isnull = cs->irb.ICmpEQ(fir::ConstantValue::getZeroValue(fir::Type::getInt8Ptr()), _ptr); cs->irb.CondBranch(isnull, merge, cond); cs->irb.setCurrentBlock(cond); { auto ch = cs->irb.ReadPtr(cs->irb.ReadPtr(ptrp)); auto isnotzero = cs->irb.ICmpNEQ(ch, c0); cs->irb.CondBranch(isnotzero, body, merge); } cs->irb.setCurrentBlock(body); { // if statement auto ch = cs->irb.ReadPtr(cs->irb.ReadPtr(ptrp)); auto mask = cs->irb.BitwiseAND(ch, cs->irb.IntSizeCast(fir::ConstantInt::getUint8(0xC0), fir::Type::getInt8())); auto isch = cs->irb.ICmpNEQ(mask, cs->irb.IntSizeCast(fir::ConstantInt::getUint8(0x80), fir::Type::getInt8())); fir::IRBlock* incr = cs->irb.addNewBlockInFunction("incr", func); fir::IRBlock* skip = cs->irb.addNewBlockInFunction("skip", func); cs->irb.CondBranch(isch, incr, skip); cs->irb.setCurrentBlock(incr); { cs->irb.WritePtr(cs->irb.Add(cs->irb.ReadPtr(lenp), i1), lenp); cs->irb.UnCondBranch(skip); } cs->irb.setCurrentBlock(skip); { auto newptr = cs->irb.GetPointer(cs->irb.ReadPtr(ptrp), i1); cs->irb.WritePtr(newptr, ptrp); cs->irb.UnCondBranch(cond); } } cs->irb.setCurrentBlock(merge); { auto len = cs->irb.ReadPtr(lenp); cs->irb.Return(len); } lenf = func; cs->irb.setCurrentBlock(restore); } iceAssert(lenf); return lenf; } } } } ================================================ FILE: source/codegen/literals.cpp ================================================ // literals.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "sst.h" #include "codegen.h" CGResult sst::LiteralNumber::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); if(this->type->isConstantNumberType()) { if(infer && !infer->isPrimitiveType()) infer = 0; return CGResult(cs->unwrapConstantNumber(fir::ConstantNumber::get(this->type->toConstantNumberType(), this->num), infer)); } else { if(this->type->isFloatingPointType()) return CGResult(fir::ConstantFP::get(this->type, this->num.toDouble())); else return CGResult(fir::ConstantInt::get(this->type, this->type->isSignedIntType() ? this->num.toLLong() : this->num.toULLong())); } } CGResult sst::LiteralArray::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); if(this->type->isArrayType()) { auto elmty = this->type->toArrayType()->getElementType(); if(fir::isRefCountedType(elmty)) error(this, "cannot have refcounted type in array literal"); std::vector vals; for(auto v : this->values) { auto cv = dcast(fir::ConstantValue, v->codegen(cs, elmty).value); if(!cv) error(v, "constant value required in fixed array literal"); if(cv->getType() != elmty) error(v, "mismatched type for array literal; expected element type '%s', found '%s'", elmty, cv->getType()); vals.push_back(cv); } // ok return CGResult(fir::ConstantArray::get(this->type, vals)); } else if(this->type->isDynamicArrayType() || this->type->isArraySliceType()) { // ok, this can basically be anything. // no restrictions. fir::Value* returnValue = 0; auto elmty = this->type->getArrayElementType(); if(this->values.empty()) { // if our element type is void, and there is no infer... die. if(!infer || (elmty->isVoidType() && infer == 0) || (infer && infer->getArrayElementType()->isVoidType())) error(this, "failed to infer type for empty array literal"); auto z = fir::ConstantInt::getNative(0); if(infer->isDynamicArrayType()) { // ok. elmty = infer->getArrayElementType(); returnValue = fir::ConstantDynamicArray::get(fir::DynamicArrayType::get(elmty), fir::ConstantValue::getZeroValue(elmty->getPointerTo()), z, z); } else if(infer->isArraySliceType()) { elmty = infer->getArrayElementType(); //* note: it's clearly a null pointer, so it must be immutable. returnValue = fir::ConstantArraySlice::get(fir::ArraySliceType::get(elmty, false), fir::ConstantValue::getZeroValue(elmty->getPointerTo()), z); } else { error(this, "incorrectly inferred type '%s' for empty array literal", infer); } } else { // make a function specifically to initialise this thing static size_t _id = 0; auto theId = _id++; auto _aty = fir::ArrayType::get(elmty, this->values.size()); auto array = cs->module->createGlobalVariable(fir::Name::obfuscate("_FV_DAR_", theId), _aty, fir::ConstantArray::getZeroValue(_aty), false, fir::LinkageType::Internal); { auto restore = cs->irb.getCurrentBlock(); fir::Function* func = cs->module->getOrCreateFunction(fir::Name::obfuscate("init_array", theId), fir::FunctionType::get({ }, fir::Type::getVoid()), fir::LinkageType::Internal); fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); cs->irb.setCurrentBlock(entry); auto arrptr = cs->irb.AddressOf(array, true); std::vector vals; for(auto v : this->values) { auto vl = v->codegen(cs, elmty).value; if(vl->getType() != elmty) vl = cs->oneWayAutocast(vl, elmty); if(vl->getType() != elmty) { error(v, "mismatched type for array literal; expected element type '%s', found '%s'", elmty, vl->getType()); } // ok, it works vals.push_back(vl); } // ok -- basically unroll the loop, except there's no loop -- so we're just... // doing a thing. for(size_t i = 0; i < vals.size(); i++) { // offset by 1 fir::Value* ptr = cs->irb.ConstGEP2(arrptr, 0, i); cs->irb.WritePtr(vals[i], ptr); } cs->irb.ReturnVoid(); cs->irb.setCurrentBlock(restore); // ok, call the function cs->irb.Call(func); } // return it if(this->type->isDynamicArrayType()) { auto arrptr = cs->irb.AddressOf(array, true); auto aa = cs->irb.CreateValue(this->type->toDynamicArrayType()); aa = cs->irb.SetSAAData(aa, cs->irb.ConstGEP2(arrptr, 0, 0)); aa = cs->irb.SetSAALength(aa, fir::ConstantInt::getNative(this->values.size())); aa = cs->irb.SetSAACapacity(aa, fir::ConstantInt::getNative(-1)); aa = cs->irb.SetSAARefCountPointer(aa, fir::ConstantValue::getZeroValue(fir::Type::getNativeWordPtr())); returnValue = aa; } else if(this->type->isArraySliceType()) { auto arrptr = cs->irb.AddressOf(array, true); auto aa = cs->irb.CreateValue(this->type->toArraySliceType()); aa = cs->irb.SetArraySliceData(aa, cs->irb.PointerTypeCast(cs->irb.ConstGEP2(arrptr, 0, 0), elmty->getPointerTo())); aa = cs->irb.SetArraySliceLength(aa, fir::ConstantInt::getNative(this->values.size())); returnValue = aa; } else { error(this, "what???"); } } iceAssert(returnValue); cs->addRAIIOrRCValueIfNecessary(returnValue); return CGResult(returnValue); } else { error(this, "what?"); } } CGResult sst::LiteralTuple::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); iceAssert(this->type->isTupleType()); bool allConst = true; std::vector vals; for(size_t i = 0; i < this->values.size(); i++) { auto ty = this->type->toTupleType()->getElementN(i); auto vr = this->values[i]->codegen(cs, ty).value; if(vr->getType() != ty) vr = cs->oneWayAutocast(vr, ty); if(vr->getType() != ty) { error(this->values[i], "mismatched types in tuple element %d; expected type '%s', found type '%s'", i, ty, vr->getType()); } allConst &= (dcast(fir::ConstantValue, vr) != nullptr); vals.push_back(vr); } if(allConst) { std::vector consts = zfu::map(vals, [](auto e) -> auto { return dcast(fir::ConstantValue, e); }); return CGResult(fir::ConstantTuple::get(consts)); } else { auto tup = cs->irb.CreateValue(this->type); for(size_t i = 0; i < vals.size(); i++) tup = cs->irb.InsertValue(tup, { i }, vals[i]); return CGResult(tup); } } CGResult sst::LiteralNull::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); fir::Value* val = 0; if(infer) val = fir::ConstantValue::getZeroValue(infer); else val = fir::ConstantValue::getNull(); return CGResult(val); } CGResult sst::LiteralBool::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); return CGResult(fir::ConstantBool::get(this->value)); } CGResult sst::LiteralChar::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); return CGResult(fir::ConstantInt::getInt8(static_cast(this->value))); } CGResult sst::LiteralString::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); // allow automatic coercion of string literals into i8* if(this->isCString || infer == fir::Type::getInt8Ptr()) { // good old i8* fir::Value* stringVal = cs->module->createGlobalString(this->str); return CGResult(stringVal); } else { auto str = cs->module->createGlobalString(this->str); auto slc = fir::ConstantArraySlice::get(fir::Type::getCharSlice(false), str, fir::ConstantInt::getNative(this->str.length())); return CGResult(slc); } } ================================================ FILE: source/codegen/logical.cpp ================================================ // logical.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "errors.h" #include "codegen.h" #include "typecheck.h" namespace cgn { static CGResult doLogicalOr(CodegenState* cs, sst::BinaryOp* b) { // use a phi thing. auto cb = cs->irb.getCurrentBlock(); auto pass = cs->irb.addNewBlockAfter("shortcircuit-or-" + b->loc.shortString(), cb); auto check = cs->irb.addNewBlockAfter("secondcond-or-" + b->loc.shortString(), pass); auto merge = cs->irb.addNewBlockAfter("merge-or-" + b->loc.shortString(), check); // ok. // always generate the first thing. fir::Value* left = b->left->codegen(cs, fir::Type::getBool()).value; if(!left->getType()->isBoolType()) error(b->left, "non-boolean type '%s' cannot be used as a conditional", left->getType()); // ok, compare first. fir::Value* cmpres = cs->irb.ICmpEQ(left, fir::ConstantBool::get(true)); cs->irb.CondBranch(cmpres, pass, check); cs->irb.setCurrentBlock(pass); { cs->irb.UnCondBranch(merge); } cs->irb.setCurrentBlock(check); { // ok, check the second fir::Value* right = b->right->codegen(cs, fir::Type::getBool()).value; if(!right->getType()->isBoolType()) error(b->right, "non-boolean type '%s' cannot be used as a conditional", right->getType()); fir::Value* cmpres = cs->irb.ICmpEQ(right, fir::ConstantBool::get(true)); cs->irb.CondBranch(cmpres, pass, merge); } auto fromBlk = cs->irb.getCurrentBlock(); cs->irb.setCurrentBlock(merge); auto phi = cs->irb.CreatePHINode(fir::Type::getBool()); phi->addIncoming(fir::ConstantBool::get(true), pass); phi->addIncoming(fir::ConstantBool::get(false), fromBlk); return CGResult(phi); } static CGResult doLogicalAnd(CodegenState* cs, sst::BinaryOp* b) { // use a phi thing. auto cb = cs->irb.getCurrentBlock(); auto fail = cs->irb.addNewBlockAfter("shortcircuit-and-" + b->loc.shortString(), cb); auto check = cs->irb.addNewBlockAfter("secondcond-and-" + b->loc.shortString(), fail); auto merge = cs->irb.addNewBlockAfter("merge-and-" + b->loc.shortString(), check); // ok. // always generate the first thing. fir::Value* left = b->left->codegen(cs, fir::Type::getBool()).value; if(!left->getType()->isBoolType()) error(b->left, "non-boolean type '%s' cannot be used as a conditional", left->getType()); // ok, compare first. fir::Value* cmpres = cs->irb.ICmpEQ(left, fir::ConstantBool::get(true)); cs->irb.CondBranch(cmpres, check, fail); cs->irb.setCurrentBlock(fail); { // break straight to merge cs->irb.UnCondBranch(merge); } cs->irb.setCurrentBlock(check); { // ok, check the second fir::Value* right = b->right->codegen(cs, fir::Type::getBool()).value; if(!right->getType()->isBoolType()) error(b->right, "non-boolean type '%s' cannot be used as a conditional", right->getType()); fir::Value* cmpres = cs->irb.ICmpEQ(right, fir::ConstantBool::get(true)); cs->irb.CondBranch(cmpres, merge, fail); } auto fromBlk = cs->irb.getCurrentBlock(); cs->irb.setCurrentBlock(merge); auto phi = cs->irb.CreatePHINode(fir::Type::getBool()); phi->addIncoming(fir::ConstantBool::get(true), fromBlk); phi->addIncoming(fir::ConstantBool::get(false), fail); return CGResult(phi); } CGResult CodegenState::performLogicalBinaryOperation(sst::BinaryOp* bo) { if(bo->op == "&&") return doLogicalAnd(this, bo); else return doLogicalOr(this, bo); } } ================================================ FILE: source/codegen/loops.cpp ================================================ // loops.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "sst.h" #include "codegen.h" #include "memorypool.h" CGResult sst::WhileLoop::_codegen(cgn::CodegenState* cs, fir::Type* inferred) { cs->pushLoc(this); defer(cs->popLoc()); if(this->isDoVariant && !this->cond) { this->body->codegen(cs); return CGResult(0); } auto loop = cs->irb.addNewBlockAfter("loop-" + this->loc.shortString(), cs->irb.getCurrentBlock()); fir::IRBlock* merge = 0; if(!this->elideMergeBlock) merge = cs->irb.addNewBlockAfter("merge-" + this->loc.shortString(), cs->irb.getCurrentBlock()); else if(!this->isDoVariant) error(this, "internal error: cannot elide merge block with non-do while loop"); auto getcond = [](cgn::CodegenState* cs, Expr* c) -> fir::Value* { auto cv = cs->oneWayAutocast(c->codegen(cs, fir::Type::getBool()).value, fir::Type::getBool()); if(cv->getType() != fir::Type::getBool()) error(c, "non-boolean expression with type '%s' cannot be used as a conditional", cv->getType()); // ok return cv; }; if(this->isDoVariant) { cs->irb.UnCondBranch(loop); cs->irb.setCurrentBlock(loop); cs->enterBreakableBody(cgn::ControlFlowPoint(this->body, merge, loop)); { this->body->codegen(cs); } cs->leaveBreakableBody(); // if merge == NULL, that means we're suppose to elide the merge block. // so, don't insert any more instructions. if(merge) { iceAssert(!cs->irb.getCurrentBlock()->isTerminated()); if(this->cond) { iceAssert(this->cond); auto condv = getcond(cs, this->cond); cs->irb.CondBranch(condv, loop, merge); } else { cs->irb.UnCondBranch(merge); } } else { iceAssert(cs->irb.getCurrentBlock()->isTerminated()); } } else { auto check = cs->irb.addNewBlockAfter("check", cs->irb.getCurrentBlock()); cs->irb.UnCondBranch(check); cs->irb.setCurrentBlock(check); // ok iceAssert(this->cond); iceAssert(merge); auto condv = getcond(cs, this->cond); cs->irb.CondBranch(condv, loop, merge); cs->irb.setCurrentBlock(loop); cs->enterBreakableBody(cgn::ControlFlowPoint(this->body, merge, check)); { this->body->codegen(cs); } cs->leaveBreakableBody(); // ok, do a jump back to the top cs->irb.UnCondBranch(check); } cs->irb.setCurrentBlock(merge); return CGResult(0); } std::vector sst::WhileLoop::getBlocks() { return { this->body }; } CGResult sst::ForeachLoop::_codegen(cgn::CodegenState* cs, fir::Type* inferred) { cs->pushLoc(this); defer(cs->popLoc()); //? this will change when we get iterators. //* but, for now, the basic model is the same for all types -- we get a pointer, we have a starting index, and we have a count. //* for ranges, we also have an increment, but for the rest it will be 1. /* init (current): int start = $start int end = $end int step = $step check: if start < end goto loop else goto merge loop: .. do things .. start += step goto check merge: .. continue .. */ // auto prevblock = cs->irb.getCurrentBlock(); auto check = cs->irb.addNewBlockAfter("check", cs->irb.getCurrentBlock()); auto loop = cs->irb.addNewBlockAfter("loop", cs->irb.getCurrentBlock()); auto merge = cs->irb.addNewBlockAfter("merge", cs->irb.getCurrentBlock()); fir::Value* end = 0; fir::Value* step = 0; fir::Value* idxptr = cs->irb.StackAlloc(fir::Type::getNativeWord()); fir::Value* iterptr = cs->irb.StackAlloc(fir::Type::getNativeWord()); auto [ array, vk ] = this->array->codegen(cs); (void) vk; if(array->getType()->isRangeType()) { cs->irb.WritePtr(cs->irb.GetRangeLower(array), idxptr); end = cs->irb.GetRangeUpper(array); step = cs->irb.GetRangeStep(array); //* overly verbose explanation: /* Here's the deal: most of the time we're dealing with arrays, so we just make this a little bit easier in that case. we compare start < end as the condition, meaning that 'end' is really a length. for ranges however, (since we normalise the half-open range to an open range), we actually want to reach the ending value. so, we just add 1 to end. this is independent of the step size. */ //! note: again for negative ranges, we should be subtracting 1 instead. end = cs->irb.Add(end, cs->irb.Select(cs->irb.ICmpGEQ(step, fir::ConstantInt::getNative(0)), fir::ConstantInt::getNative(1), fir::ConstantInt::getNative(-1))); } else { cs->irb.WritePtr(fir::ConstantInt::getNative(0), idxptr); step = fir::ConstantInt::getNative(1); if(array->getType()->isDynamicArrayType()) { end = cs->irb.GetSAALength(array); } else if(array->getType()->isArraySliceType()) { end = cs->irb.GetArraySliceLength(array); } else if(array->getType()->isStringType()) { end = cs->irb.GetSAALength(array); } else if(array->getType()->isArrayType()) { end = fir::ConstantInt::getNative(array->getType()->toArrayType()->getArraySize()); } else { error(this->array, "unsupported type '%s' in foreach loop", array->getType()); } } cs->irb.UnCondBranch(check); cs->irb.setCurrentBlock(check); //! here's some special shit where we handle ranges with start > end fir::Value* cond = 0; if(array->getType()->isRangeType()) { cond = cs->irb.Select(cs->irb.ICmpGT(step, fir::ConstantInt::getNative(0)), cs->irb.ICmpLT(cs->irb.ReadPtr(idxptr), end), // i < end for step > 0 cs->irb.ICmpGT(cs->irb.ReadPtr(idxptr), end)); // i > end for step < 0 } else { cond = cs->irb.ICmpLT(cs->irb.ReadPtr(idxptr), end); } iceAssert(cond); cs->irb.CondBranch(cond, loop, merge); cs->irb.setCurrentBlock(loop); { fir::Value* theptr = 0; if(array->getType()->isRangeType()) theptr = idxptr; else if(array->getType()->isDynamicArrayType()) theptr = cs->irb.GetPointer(cs->irb.GetSAAData(array), cs->irb.ReadPtr(idxptr)); else if(array->getType()->isArraySliceType()) theptr = cs->irb.GetPointer(cs->irb.GetArraySliceData(array), cs->irb.ReadPtr(idxptr)); else if(array->getType()->isStringType()) theptr = cs->irb.PointerTypeCast(cs->irb.GetPointer(cs->irb.GetSAAData(array), cs->irb.ReadPtr(idxptr)), fir::Type::getInt8Ptr()); else if(array->getType()->isArrayType()) { fir::Value* arrptr = 0; if(array->islvalue()) { arrptr = cs->irb.AddressOf(array, false); } else { arrptr = cs->irb.CreateLValue(array->getType()); cs->irb.Store(array, arrptr); arrptr->makeConst(); } theptr = cs->irb.GetPointer(cs->irb.ConstGEP2(arrptr, 0, 0), cs->irb.ReadPtr(idxptr)); } else { iceAssert(0); } // make the block cs->enterBreakableBody(cgn::ControlFlowPoint(this->body, merge, check)); { // msvc: structured bindings cannot be captured // what the FUCK??? auto _array = array; this->body->preBodyCode = [cs, theptr, _array, iterptr, this]() { // TODO: is this correct??? auto res = CGResult(cs->irb.Dereference(theptr)); cs->generateDecompositionBindings(this->mappings, res, !(_array->getType()->isRangeType() || _array->getType()->isStringType())); if(this->indexVar) { auto idx = util::pool(this->indexVar->loc, fir::Type::getNativeWord()); idx->rawValue = CGResult(cs->irb.ReadPtr(iterptr)); this->indexVar->init = idx; this->indexVar->codegen(cs); } }; this->body->codegen(cs); } cs->leaveBreakableBody(); // increment the index cs->irb.WritePtr(cs->irb.Add(cs->irb.ReadPtr(idxptr), step), idxptr); cs->irb.WritePtr(cs->irb.Add(cs->irb.ReadPtr(iterptr), fir::ConstantInt::getNative(1)), iterptr); cs->irb.UnCondBranch(check); } cs->irb.setCurrentBlock(merge); return CGResult(0); } std::vector sst::ForeachLoop::getBlocks() { return { this->body }; } ================================================ FILE: source/codegen/misc.cpp ================================================ // misc.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "sst.h" #include "codegen.h" CGResult sst::TypeExpr::_codegen(cgn::CodegenState* cs, fir::Type* infer) { return CGResult(fir::ConstantValue::getZeroValue(this->type)); } CGResult sst::ScopeExpr::_codegen(cgn::CodegenState* cs, fir::Type* infer) { error(this, "failed to resolve scope '%s'", this->scope.string()); } CGResult sst::BareTypeDefn::_codegen(cgn::CodegenState* cs, fir::Type* infer) { // there's nothing to do here... cs->pushLoc(this); defer(cs->popLoc()); return CGResult(0); } CGResult sst::Stmt::codegen(cgn::CodegenState* cs, fir::Type* inferred) { return this->_codegen(cs, inferred); } CGResult sst::Defn::codegen(cgn::CodegenState* cs, fir::Type* inferred) { if(this->didCodegen && cs->id == this->cachedCSId) return this->cachedResult; this->didCodegen = true; this->cachedCSId = cs->id; return (this->cachedResult = this->_codegen(cs, inferred)); } // TODO: move this impl somewhere else? sst::FunctionDefn* cgn::CodegenState::findMatchingMethodInType(sst::TypeDefn* td, sst::FunctionDecl* fn) { if(auto str = dcast(sst::StructDefn, td); str) { // TODO: when (if) we figure out what's going on in typecheck/traits.cpp:129, possibly change this to match. auto it = std::find_if(str->methods.begin(), str->methods.end(), [fn](sst::FunctionDefn* method) -> bool { //* i think this check should work, `areMethodsVirtuallyCompatible` basically checks the parameters but takes //* co/contravariance into account and doesn't match the first (self) parameter. return (fn->id.name == method->id.name && fir::areMethodsVirtuallyCompatible( fn->type->toFunctionType(), method->type->toFunctionType(), /* checking trait: */ true) ); }); if(it != str->methods.end()) return *it; } return 0; } ================================================ FILE: source/codegen/operators.cpp ================================================ // operators.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "sst.h" #include "codegen.h" namespace cgn { using OperatorFn = CodegenState::OperatorFn; std::pair CodegenState::getOperatorFunctionForTypes(fir::Type* a, fir::Type* b, std::string op) { std::function isBuiltinType = [&](fir::Type* t) -> bool { if(t->isPrimitiveType()) return true; else if(t->isBoolType()) return true; else if(t->isCharType()) return true; else if(t->isStringType()) return true; else if(t->isNullType()) return true; else if(t->isVoidType()) return true; else if(t->isPointerType()) return true; else if(t->isArrayType() || t->isDynamicArrayType() || t->isArraySliceType()) { return isBuiltinType(t->getArrayElementType()); } else if(t->isTupleType()) { // uhm... bool res = false; for(auto e : t->toTupleType()->getElements()) res &= isBuiltinType(e); return res; } else { return false; } }; // check what the thing is if(isBuiltinType(a) && isBuiltinType(b)) { return { OperatorFn::Builtin, 0 }; } else { error(this->loc(), "unsupported operator function '%s' on types '%s' and '%s'", op, a, b); } } } ================================================ FILE: source/codegen/raii.cpp ================================================ // raii.cpp // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. #include "sst.h" #include "codegen.h" #include "string_consts.h" namespace cgn { void CodegenState::addRAIIValue(fir::Value* val) { // TODO: we need global destructors eventually. if(this->isWithinGlobalInitFunction()) return; if(!this->isRAIIType(val->getType())) error("val is not a class type! '%s'", val->getType()); auto list = &this->blockPointStack.back().raiiValues; if(auto it = std::find(list->begin(), list->end(), val); it == list->end()) { list->push_back(val); } else { error("adding duplicate raii value (ptr = %p, type = '%s')", reinterpret_cast(val), val->getType()); } } void CodegenState::removeRAIIValue(fir::Value* val) { // TODO: we need global destructors eventually. if(this->isWithinGlobalInitFunction()) return; if(!this->isRAIIType(val->getType())) error("val is not a class type! '%s'", val->getType()); auto list = &this->blockPointStack.back().raiiValues; if(auto it = std::find(list->begin(), list->end(), val); it != list->end()) { list->erase(it); } else { error("removing non-existent raii value (ptr = %p, type = '%s')", reinterpret_cast(val), val->getType()); } } std::vector CodegenState::getRAIIValues() { return this->blockPointStack.back().raiiValues; } void CodegenState::addRAIIOrRCValueIfNecessary(fir::Value* val, fir::Type* ty) { if(!ty) ty = val->getType(); if(fir::isRefCountedType(ty)) this->addRefCountedValue(val); if(this->isRAIIType(ty)) this->addRAIIValue(val); } static fir::Value* getAddressOfOrMakeTemporaryLValue(CodegenState* cs, fir::Value* val, bool mut) { if(val->islvalue()) { return cs->irb.AddressOf(val, mut); } else { auto tmp = cs->irb.CreateLValue(val->getType()); cs->irb.Store(val, tmp); return cs->irb.AddressOf(tmp, mut); } } static fir::Function* getImplementationForRAIITrait(CodegenState* cs, const std::string& name, fir::Type* ty) { if(auto it = cs->compilerSupportDefinitions.find(name); it != cs->compilerSupportDefinitions.end()) { auto trt = dcast(sst::TraitDefn, it->second); if(!trt) error("invalid use of @compiler_support[\"%s\"] on non-trait definition!", name); iceAssert(trt->methods.size() == 1); auto str = dcast(sst::StructDefn, cs->typeDefnMap[ty]); iceAssert(str); auto target = cs->findMatchingMethodInType(str, trt->methods[0]); if(target) { // the inferred type should be the receiver type auto ret = target->codegen(cs, ty); return dcast(fir::Function, ret.value); } } return 0; } void CodegenState::callDestructor(fir::Value* val) { if(!this->typeHasDestructor(val->getType())) return; fir::Value* selfptr = getAddressOfOrMakeTemporaryLValue(this, val, /* mutable: */ true); if(val->getType()->isClassType()) { auto cls = val->getType()->toClassType(); // call the user-defined one first, if any: if(auto des = cls->getDestructor(); des) this->irb.Call(des, selfptr); // call the auto one. this will handle calling base class destructors for us! this->irb.Call(cls->getInlineDestructor(), selfptr); } else { auto destructor = getImplementationForRAIITrait(this, strs::names::support::RAII_TRAIT_DROP, val->getType()); // well if you didn't implement it then the typechecker would have already complained about you so... iceAssert(destructor); this->irb.Call(destructor, selfptr); } } static void doMemberWiseStuffIfNecessary(CodegenState* cs, fir::ClassType* clsty, fir::Value* from, fir::Value* target, bool move) { // check if there are even any class types inside. if not, do the simple thing! bool needSpecial = false; for(auto m : clsty->getElements()) { if(m->isClassType()) { needSpecial = true; break; } } if(needSpecial) { auto selfptr = getAddressOfOrMakeTemporaryLValue(cs, target, true); auto otherptr = getAddressOfOrMakeTemporaryLValue(cs, from, true); // assign `lhs = rhs` for(const auto& name : clsty->getNameList()) { auto lhs = cs->irb.GetStructMember(cs->irb.Dereference(selfptr), name); auto rhs = cs->irb.GetStructMember(cs->irb.Dereference(otherptr), name); if(move) cs->moveRAIIValue(rhs, lhs); else cs->copyRAIIValue(rhs, lhs); } } else { cs->irb.Store(from, target); } } fir::Value* CodegenState::copyRAIIValue(fir::Value* value) { if(!typeHasCopyConstructor(value->getType())) return value; // this will zero-initialise! auto ret = this->irb.CreateLValue(value->getType()); this->copyRAIIValue(value, ret, /* enableMoving: */ false); return ret; } void CodegenState::copyRAIIValue(fir::Value* from, fir::Value* target, bool enableMoving) { iceAssert(from->getType() == target->getType()); if(!typeHasCopyConstructor(from->getType())) { this->irb.Store(from, target); return; } if(!from->islvalue() && enableMoving) { this->moveRAIIValue(from, target); return; } // there's probably a better way to structure this, but i can't be bothered right now // or ever. it's just 2 lines of code dupe anyway. so sue me. if(from->getType()->isClassType()) { auto clsty = from->getType()->toClassType(); // if there is a copy-constructor, then we will call the copy constructor. if(auto copycon = clsty->getCopyConstructor(); copycon) { // note: we make otherptr immutable, because copy() isn't supposed to pass the thing mutably! auto selfptr = getAddressOfOrMakeTemporaryLValue(this, target, true); auto otherptr = getAddressOfOrMakeTemporaryLValue(this, from, false); this->irb.Call(copycon, selfptr, otherptr); } else { doMemberWiseStuffIfNecessary(this, clsty, from, target, /* move: */ false); } } else { // note: we make otherptr immutable, because copy() isn't supposed to pass the thing mutably! auto selfptr = getAddressOfOrMakeTemporaryLValue(this, target, true); auto otherptr = getAddressOfOrMakeTemporaryLValue(this, from, false); // well we got here, so we know at least the type has a copy constructor somewhere. auto copycon = getImplementationForRAIITrait(this, strs::names::support::RAII_TRAIT_COPY, from->getType()); // again, typechecking would have complained prior to this iceAssert(copycon); this->irb.Call(copycon, selfptr, otherptr); } } void CodegenState::moveRAIIValue(fir::Value* from, fir::Value* target) { iceAssert(from->getType() == target->getType()); if(!typeHasMoveConstructor(from->getType()) || from->islvalue()) { // you can't move from lvalues! this->copyRAIIValue(from, target); return; } if(from->getType()->isClassType()) { auto clsty = from->getType()->toClassType(); // if there is a copy-constructor, then we will call the copy constructor. if(auto movecon = clsty->getMoveConstructor(); movecon) { // note: here both are mutable. auto selfptr = getAddressOfOrMakeTemporaryLValue(this, target, true); auto otherptr = getAddressOfOrMakeTemporaryLValue(this, from, true); this->irb.Call(movecon, selfptr, otherptr); } else { doMemberWiseStuffIfNecessary(this, clsty, from, target, /* move: */ true); } } else { // note: here both are mutable. auto selfptr = getAddressOfOrMakeTemporaryLValue(this, target, true); auto otherptr = getAddressOfOrMakeTemporaryLValue(this, from, true); // well we got here, so we know at least the type has a copy constructor somewhere. auto movecon = getImplementationForRAIITrait(this, strs::names::support::RAII_TRAIT_MOVE, from->getType()); // again, typechecking would have complained prior to this iceAssert(movecon); this->irb.Call(movecon, selfptr, otherptr); } this->removeRAIIValue(from); } // TODO: memoise this for each type; the typeHas-blalba ones also! static bool findRAIITraitImpl(CodegenState* cs, fir::Type* ty, const std::string& name) { if(ty->isClassType()) return true; if(!ty->isStructType()) return false; auto str = ty->toStructType(); auto def = dcast(sst::StructDefn, cs->typeDefnMap[str]); iceAssert(def); return zfu::matchAny(def->traits, [name](sst::TraitDefn* trt) -> bool { // if we do not have such an attribute, then ::get returns an empty UA, // with an empty string as a name. return trt->attrs.get(strs::attrs::COMPILER_SUPPORT).name == strs::attrs::COMPILER_SUPPORT; }); } bool CodegenState::typeHasDestructor(fir::Type* ty) { return findRAIITraitImpl(this, ty, strs::names::support::RAII_TRAIT_DROP); } bool CodegenState::typeHasCopyConstructor(fir::Type* ty) { return findRAIITraitImpl(this, ty, strs::names::support::RAII_TRAIT_COPY); } bool CodegenState::typeHasMoveConstructor(fir::Type* ty) { return findRAIITraitImpl(this, ty, strs::names::support::RAII_TRAIT_MOVE); } bool CodegenState::isRAIIType(fir::Type* ty) { return this->typeHasDestructor(ty) || this->typeHasCopyConstructor(ty) || this->typeHasMoveConstructor(ty); } } ================================================ FILE: source/codegen/ranges.cpp ================================================ // ranges.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "sst.h" #include "codegen.h" #include "gluecode.h" CGResult sst::RangeExpr::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); auto start = cs->oneWayAutocast(this->start->codegen(cs, fir::Type::getNativeWord()).value, fir::Type::getNativeWord()); iceAssert(start); if(!start->getType()->isIntegerType()) error(this->start, "expected integer type in range expression (start), found '%s' instead", start->getType()); auto end = cs->oneWayAutocast(this->end->codegen(cs, fir::Type::getNativeWord()).value, fir::Type::getNativeWord()); iceAssert(end); if(!end->getType()->isIntegerType()) error(this->end, "expected integer type in range expression (end), found '%s' instead", end->getType()); // if we're half-open, then we need to subtract 1 from the end value. // TODO: do we need to check for start > end for half open? // it's well documented that we always subtract 1 for half open, but it might be immediately obvious. if(this->halfOpen) end = cs->irb.Subtract(end, fir::ConstantInt::getNative(1)); // if start > end, the automatic step should be -1. else, it should be 1 as normal. fir::Value* step = (this->step ? cs->oneWayAutocast(this->step->codegen(cs, fir::Type::getNativeWord()).value, fir::Type::getNativeWord()) : cs->irb.Select(cs->irb.ICmpLEQ(start, end), fir::ConstantInt::getNative(1), fir::ConstantInt::getNative(-1)) ); iceAssert(step); if(!step->getType()->isIntegerType()) error(this->step, "expected integer type in range expression (step), found '%s' instead", step->getType()); auto ret = cs->irb.CreateValue(fir::RangeType::get()); ret = cs->irb.SetRangeLower(ret, start); ret = cs->irb.SetRangeUpper(ret, end); ret = cs->irb.SetRangeStep(ret, step); // now that we have all the values, it's time to sanity check these things. auto checkf = cgn::glue::misc::getRangeSanityCheckFunction(cs); if(checkf) cs->irb.Call(checkf, ret, fir::ConstantCharSlice::get(this->loc.toString())); return CGResult(ret); } ================================================ FILE: source/codegen/refcounting.cpp ================================================ // refcounting.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "sst.h" #include "codegen.h" #include "gluecode.h" namespace cgn { void CodegenState::addRefCountedValue(fir::Value* val) { if(this->isWithinGlobalInitFunction()) return; auto list = &this->blockPointStack.back().refCountedValues; if(auto it = std::find(list->begin(), list->end(), val); it == list->end()) { list->push_back(val); } else { error(this->loc(), "adding duplicate refcounted value (ptr = %p, type = '%s')", reinterpret_cast(val), val->getType()); } } void CodegenState::removeRefCountedValue(fir::Value* val) { if(this->isWithinGlobalInitFunction()) return; auto list = &this->blockPointStack.back().refCountedValues; if(auto it = std::find(list->begin(), list->end(), val); it != list->end()) { list->erase(it); } else { error(this->loc(), "removing non-existent refcounted value (ptr = %p, type = '%s')", reinterpret_cast(val), val->getType()); } } std::vector CodegenState::getRefCountedValues() { return this->blockPointStack.back().refCountedValues; } void CodegenState::autoAssignRefCountedValue(fir::Value* lhs, fir::Value* rhs, bool isinit) { iceAssert(lhs && rhs); if(!lhs->islvalue()) error(this->loc(), "assignment (move) to non-lvalue and non-pointer (type '%s')", lhs->getType()); if(fir::isRefCountedType(rhs->getType())) { if(!isinit) this->decrementRefCount(lhs); if(rhs->canmove()) { this->removeRefCountedValue(rhs); } else { this->incrementRefCount(rhs); } } // copy will do the right thing in all cases (handle non-RAII, and call move if possible) this->copyRAIIValue(rhs, lhs); } static bool isStructuredAggregate(fir::Type* t) { return t->isStructType() || t->isClassType() || t->isTupleType(); } template void doRefCountOfAggregateType(CodegenState* cs, T* type, fir::Value* value, bool incr) { size_t i = 0; for(auto m : type->getElements()) { if(fir::isRefCountedType(m)) { fir::Value* mem = cs->irb.ExtractValue(value, { i }); if(incr) cs->incrementRefCount(mem); else cs->decrementRefCount(mem); } else if(isStructuredAggregate(m)) { fir::Value* mem = cs->irb.ExtractValue(value, { i }); if(m->isStructType()) doRefCountOfAggregateType(cs, m->toStructType(), mem, incr); else if(m->isClassType()) doRefCountOfAggregateType(cs, m->toClassType(), mem, incr); else if(m->isTupleType()) doRefCountOfAggregateType(cs, m->toTupleType(), mem, incr); } i++; } } static void _doRefCount(CodegenState* cs, fir::Value* val, bool incr) { auto type = val->getType(); if(type->isStringType()) { fir::Function* rf = 0; if(incr) rf = glue::string::getRefCountIncrementFunction(cs); else rf = glue::string::getRefCountDecrementFunction(cs); cs->irb.Call(rf, val); } else if(isStructuredAggregate(type)) { auto ty = type; if(ty->isStructType()) doRefCountOfAggregateType(cs, ty->toStructType(), val, incr); else if(ty->isClassType()) doRefCountOfAggregateType(cs, ty->toClassType(), val, incr); else if(ty->isTupleType()) doRefCountOfAggregateType(cs, ty->toTupleType(), val, incr); } else if(type->isDynamicArrayType()) { fir::Function* rf = 0; if(incr) rf = glue::array::getIncrementArrayRefCountFunction(cs, type->toDynamicArrayType()); else rf = glue::array::getDecrementArrayRefCountFunction(cs, type->toDynamicArrayType()); iceAssert(rf); cs->irb.Call(rf, val); } else if(type->isArrayType()) { error("no array"); } else if(type->isAnyType()) { fir::Function* rf = 0; if(incr) rf = glue::any::getRefCountIncrementFunction(cs); else rf = glue::any::getRefCountDecrementFunction(cs); cs->irb.Call(rf, val); } else { error("no: '%s'", type); } } void CodegenState::incrementRefCount(fir::Value* val) { iceAssert(fir::isRefCountedType(val->getType())); _doRefCount(this, val, true); } void CodegenState::decrementRefCount(fir::Value* val) { iceAssert(fir::isRefCountedType(val->getType())); _doRefCount(this, val, false); } } ================================================ FILE: source/codegen/sizeof.cpp ================================================ // sizeof.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "sst.h" #include "codegen.h" CGResult sst::SizeofOp::_codegen(cgn::CodegenState* cs, fir::Type* inferred) { cs->pushLoc(this); defer(cs->popLoc()); auto sz = fir::ConstantInt::getNative(fir::getSizeOfType(this->typeToSize)); return CGResult(sz); } CGResult sst::TypeidOp::_codegen(cgn::CodegenState* cs, fir::Type* inferred) { cs->pushLoc(this); defer(cs->popLoc()); auto sz = fir::ConstantInt::getUNative(this->typeToId->getID()); return CGResult(sz); } ================================================ FILE: source/codegen/slice.cpp ================================================ // slice.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "sst.h" #include "codegen.h" #include "platform.h" #include "gluecode.h" #include "memorypool.h" static void checkSliceOperation(cgn::CodegenState* cs, sst::Expr* user, fir::Value* maxlen, fir::Value* beginIndex, fir::Value* endIndex, sst::Expr* bexpr, sst::Expr* eexpr) { Location apos = (bexpr ? bexpr->loc : user->loc); Location bpos = (eexpr ? eexpr->loc : user->loc); iceAssert(beginIndex); iceAssert(endIndex); if(!beginIndex->getType()->isIntegerType()) error(bexpr, "expected integer type for array slice; got '%s'", beginIndex->getType()); if(!endIndex->getType()->isIntegerType()) error(eexpr, "expected integer type for array slice; got '%s'", endIndex->getType()); // do a check auto neg_begin = cs->irb.addNewBlockInFunction("neg_begin", cs->irb.getCurrentFunction()); auto neg_end = cs->irb.addNewBlockInFunction("neg_end", cs->irb.getCurrentFunction()); auto neg_len = cs->irb.addNewBlockInFunction("neg_len", cs->irb.getCurrentFunction()); auto check1 = cs->irb.addNewBlockInFunction("check1", cs->irb.getCurrentFunction()); auto check2 = cs->irb.addNewBlockInFunction("check2", cs->irb.getCurrentFunction()); auto merge = cs->irb.addNewBlockInFunction("merge", cs->irb.getCurrentFunction()); { fir::Value* neg = cs->irb.ICmpLT(beginIndex, fir::ConstantInt::getNative(0)); cs->irb.CondBranch(neg, neg_begin, check1); } cs->irb.setCurrentBlock(check1); { fir::Value* neg = cs->irb.ICmpLT(endIndex, fir::ConstantInt::getNative(0)); cs->irb.CondBranch(neg, neg_end, check2); } cs->irb.setCurrentBlock(check2); { fir::Value* neg = cs->irb.ICmpLT(endIndex, beginIndex); cs->irb.CondBranch(neg, neg_len, merge); } cs->irb.setCurrentBlock(neg_begin); cgn::glue::printRuntimeError(cs, fir::ConstantCharSlice::get(apos.toString()), "slice start index '%ld' is < 0\n", { beginIndex }); cs->irb.setCurrentBlock(neg_end); cgn::glue::printRuntimeError(cs, fir::ConstantCharSlice::get(bpos.toString()), "slice end index '%ld' is < 0\n", { endIndex }); cs->irb.setCurrentBlock(neg_len); cgn::glue::printRuntimeError(cs, fir::ConstantCharSlice::get(bpos.toString()), "slice end index '%ld' is < start index '%ld'\n", { endIndex, beginIndex }); cs->irb.setCurrentBlock(merge); // bounds check. { // endindex is non-inclusive -- if we're doing a decomposition check then it compares length instead // of indices here. fir::Function* checkf = cgn::glue::array::getBoundsCheckFunction(cs, /* isPerformingDecomposition: */ true); if(checkf) cs->irb.Call(checkf, maxlen, endIndex, fir::ConstantCharSlice::get(apos.toString())); } } static CGResult performSliceOperation(cgn::CodegenState* cs, sst::SliceOp* user, bool check, fir::Type* elmType, fir::Value* data, fir::Value* maxlen, fir::Value* beginIndex, fir::Value* endIndex, sst::Expr* bexpr, sst::Expr* eexpr) { if(check) checkSliceOperation(cs, user, maxlen, beginIndex, endIndex, bexpr, eexpr); // ok, make the slice fir::Type* slct = user->type; iceAssert(slct->isArraySliceType()); fir::Value* slice = cs->irb.CreateValue(slct, "slice"); // FINALLY. // increment ptr fir::Value* newptr = cs->irb.GetPointer(data, beginIndex, "newptr"); fir::Value* newlen = cs->irb.Subtract(endIndex, beginIndex, "newlen"); slice = cs->irb.SetArraySliceData(slice, newptr); slice = cs->irb.SetArraySliceLength(slice, newlen); // slices are rvalues return CGResult(slice); } CGResult sst::SliceOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); auto ty = this->expr->type; auto res = this->expr->codegen(cs); auto lhs = res.value; iceAssert(ty == lhs->getType()); fir::Value* length = 0; if(ty->isDynamicArrayType()) length = cs->irb.GetSAALength(lhs, "orig_len"); else if(ty->isArraySliceType()) length = cs->irb.GetArraySliceLength(lhs, "orig_len"); else if(ty->isStringType()) length = cs->irb.GetSAALength(lhs, "orig_len"); else if(ty->isArrayType()) length = fir::ConstantInt::getNative(ty->toArrayType()->getArraySize()); else if(ty->isPointerType()) length = fir::ConstantInt::getNative(0); else error(this, "unsupported type '%s'", ty); fir::Value* beginIdx = 0; fir::Value* endIdx = 0; iceAssert(length); { // add the dollar value. cs->enterSubscriptWithLength(length); defer(cs->leaveSubscript()); if(ty->isPointerType() && !this->end) error(this, "slicing operation on pointers requires an ending index"); if(this->begin) beginIdx = this->begin->codegen(cs).value; else beginIdx = fir::ConstantInt::getNative(0); if(this->end) endIdx = this->end->codegen(cs).value; else endIdx = length; beginIdx = cs->oneWayAutocast(beginIdx, fir::Type::getNativeWord()); endIdx = cs->oneWayAutocast(endIdx, fir::Type::getNativeWord()); } beginIdx->setName("begin"); endIdx->setName("end"); /* as a reminder: performSliceOperation( cgn::CodegenState* cs, sst::Expr* user, bool check, fir::Type* elmType, fir::Value* data, fir::Value* maxlen, fir::Value* beginIndex, fir::Value* endIndex, sst::Expr* bexpr, sst::Expr* eexpr) */ //* note: mutability determination is done at the typechecking phase. if(ty->isPointerType()) { return performSliceOperation(cs, this, false, ty->getPointerElementType(), lhs, length, beginIdx, endIdx, this->begin, this->end); } else if(ty->isDynamicArrayType()) { return performSliceOperation(cs, this, true, ty->getArrayElementType(), cs->irb.GetSAAData(lhs), length, beginIdx, endIdx, this->begin, this->end); } else if(ty->isArrayType()) { // TODO: LVALUE HOLE fir::Value* lhsptr = 0; if(!lhsptr) lhsptr = cs->irb.ImmutStackAlloc(lhs->getType(), lhs); iceAssert(lhsptr); fir::Value* data = cs->irb.ConstGEP2(lhsptr, 0, 0); return performSliceOperation(cs, this, true, ty->getArrayElementType(), data, length, beginIdx, endIdx, this->begin, this->end); } else if(ty->isArraySliceType()) { return performSliceOperation(cs, this, true, ty->getArrayElementType(), cs->irb.GetArraySliceData(lhs), length, beginIdx, endIdx, this->begin, this->end); } else if(ty->isStringType()) { return performSliceOperation(cs, this, true, fir::Type::getInt8(), cs->irb.GetSAAData(lhs), length, beginIdx, endIdx, this->begin, this->end); } else { error(this, "cannot slice unsupported type '%s'", ty); } } CGResult sst::SplatExpr::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); // right. what we want to do is to see the kind of shit that we have. auto ty = this->inside->type; if(ty->isArraySliceType()) { if(ty->isVariadicArrayType()) { auto ret = this->inside->codegen(cs, infer); iceAssert(ret->getType()->isVariadicArrayType()); return ret; } else { auto ret = this->inside->codegen(cs, infer); iceAssert(ret->getType()->isArraySliceType()); return CGResult(cs->irb.Bitcast(ret.value, fir::ArraySliceType::getVariadic(ret->getType()->getArrayElementType()))); } } else if(ty->isDynamicArrayType() || ty->isArrayType()) { // just do a slice on it. auto target = fir::ArraySliceType::getVariadic(ty->getArrayElementType()); auto slice = util::pool(this->loc, target); slice->expr = this->inside; slice->begin = 0; slice->end = 0; auto ret = slice->codegen(cs, infer); return CGResult(cs->irb.Bitcast(ret.value, target)); } else { error(this, "unexpected type '%s' in splat expression", ty); } } ================================================ FILE: source/codegen/structs.cpp ================================================ // structs.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "errors.h" #include "codegen.h" #include "typecheck.h" CGResult sst::StructDefn::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); iceAssert(this->type && this->type->isStructType()); for(auto method : this->methods) method->codegen(cs); return CGResult(0); } ================================================ FILE: source/codegen/subscript.cpp ================================================ // subscript.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "sst.h" #include "codegen.h" #include "gluecode.h" CGResult sst::SubscriptOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); // check what's the left auto lr = this->expr->codegen(cs); auto lt = lr.value->getType(); fir::Value* datapointer = 0; fir::Value* maxlength = 0; if(lt->isStringType() || lt->isDynamicArrayType()) { datapointer = cs->irb.GetSAAData(lr.value); maxlength = cs->irb.GetSAALength(lr.value); } else if(lt->isArraySliceType()) { datapointer = cs->irb.GetArraySliceData(lr.value); maxlength = cs->irb.GetArraySliceLength(lr.value); } else if(lt->isArrayType()) { // TODO: LVALUE HOLE if(lr->islvalue()) { datapointer = cs->irb.ConstGEP2(cs->irb.AddressOf(lr.value, true), 0, 0); maxlength = fir::ConstantInt::getNative(lt->toArrayType()->getArraySize()); } else { error("NOT SUP"); } } else if(lt->isPointerType()) { datapointer = lr.value; maxlength = 0; } else { iceAssert(0 && "how?"); } // first gen the inside fir::Value* index = this->inside->codegen(cs).value; { if(index->getType()->isConstantNumberType()) { auto cv = dcast(fir::ConstantValue, index); iceAssert(cv); index = cs->unwrapConstantNumber(cv); } // of course these will have to be changed eventually iceAssert(index->getType()->isIntegerType()); } if(maxlength) { fir::Function* checkf = cgn::glue::saa_common::generateBoundsCheckFunction(cs, /* isString: */ lt->isStringType(), /* isDecomp: */false); if(checkf) cs->irb.Call(checkf, maxlength, index, fir::ConstantCharSlice::get(this->loc.shortString())); } // ok, do it fir::Value* ptr = cs->irb.GetPointer(datapointer, index); return CGResult(cs->irb.Dereference(ptr)); } CGResult sst::SubscriptDollarOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); return CGResult(cs->getCurrentSubscriptArrayLength()); } ================================================ FILE: source/codegen/toplevel.cpp ================================================ // toplevel.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "sst.h" #include "errors.h" #include "codegen.h" #include "typecheck.h" #include "ir/type.h" #include "ir/module.h" #include "ir/interp.h" #include "ir/irbuilder.h" #include "memorypool.h" namespace cgn { static size_t csid = 0; CodegenState::CodegenState(const fir::IRBuilder& i) : irb(i) { this->id = csid++; } fir::Module* codegen(sst::DefinitionTree* dtr) { auto mod = new fir::Module(dtr->base->name); auto builder = fir::IRBuilder(mod); auto cs = new CodegenState(builder); cs->module = mod; cs->typeDefnMap = dtr->typeDefnMap; cs->compilerSupportDefinitions = dtr->compilerSupportDefinitions; { cs->pushLoc(dtr->topLevel); defer(cs->popLoc()); dtr->topLevel->codegen(cs); cs->finishGlobalInitFunction(); } mod->setEntryFunction(cs->entryFunction.first); delete cs; return mod; } } CGResult sst::NamespaceDefn::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); for(auto stmt : this->statements) stmt->codegen(cs); return CGResult(0); } ================================================ FILE: source/codegen/traits.cpp ================================================ // traits.cpp // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. #include "errors.h" #include "codegen.h" #include "typecheck.h" CGResult sst::TraitDefn::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); return CGResult(0); } ================================================ FILE: source/codegen/unions.cpp ================================================ // unions.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "sst.h" #include "codegen.h" CGResult sst::UnionDefn::_codegen(cgn::CodegenState* cs, fir::Type* infer) { // there's actually nothing to do. // nothing at all. return CGResult(0); } CGResult sst::UnionVariantDefn::_codegen(cgn::CodegenState* cs, fir::Type* infer) { return CGResult(0); } CGResult sst::RawUnionDefn::_codegen(cgn::CodegenState* cs, fir::Type* infer) { // again, does nothing. return CGResult(0); } CGResult sst::UnionVariantConstructor::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); auto ut = this->parentUnion->type->toUnionType(); iceAssert(ut); auto vt = ut->getVariant(this->variantId)->getInteriorType(); iceAssert(vt); auto uv = cs->irb.CreateValue(ut); if(this->args.size() > 0) { fir::Value* data = 0; if(this->args.size() == 1) { data = this->args[0].value->codegen(cs, vt).value; data = cs->oneWayAutocast(data, vt); iceAssert(data); } else { auto tupt = fir::TupleType::get(zfu::map(this->args, [](const FnCallArgument& fca) -> fir::Type* { return fca.value->type; })); auto tup = cs->irb.CreateValue(tupt); size_t i = 0; for(const auto& arg : this->args) { auto v = arg.value->codegen(cs, tupt->getElementN(i)).value; tup = cs->irb.InsertValue(tup, { i }, v); i++; } tup = cs->oneWayAutocast(tup, vt); iceAssert(tup); data = tup; } uv = cs->irb.SetUnionVariantData(uv, this->variantId, data); } uv = cs->irb.SetUnionVariantID(uv, this->variantId); return CGResult(uv); } ================================================ FILE: source/codegen/variable.cpp ================================================ // variable.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "sst.h" #include "codegen.h" CGResult sst::VarDefn::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); auto checkStore = [this, cs](fir::Value* val) -> fir::Value* { iceAssert(val); fir::Value* nv = val; if(nv->getType() != this->type) nv = cs->oneWayAutocast(nv, this->type); if(nv->getType() != this->type) { iceAssert(this->init); SpanError::make(SimpleError::make(this->loc, "cannot initialise variable of type '%s' with a value of type '%s'", this->type, nv->getType())) ->add(util::ESpan(this->init->loc, strprintf("type '%s'", nv->getType()))) ->postAndQuit(); } return nv; }; if(auto it = cs->typeDefnMap.find(this->type); it != cs->typeDefnMap.end()) it->second->codegen(cs); if(this->global) { //* note: we declare it as not-immutable here to make it easier to set things, //* but otherwise we make it immutable again below after init. auto glob = cs->module->createGlobalVariable(this->id.convertToName(), this->type, false, this->visibility == VisibilityLevel::Public ? fir::LinkageType::External : fir::LinkageType::Internal); auto rest = cs->enterGlobalInitFunction(glob); fir::Value* res = 0; if(this->init) res = this->init->codegen(cs, this->type).value; else res = cs->getDefaultValue(this->type); if(auto cv = dcast(fir::ConstantValue, res); cv && cv->getType() == this->type) { glob->setInitialValue(cv); } else { res = checkStore(res); cs->autoAssignRefCountedValue(glob, res, true); } // go and fix the thing. if(this->immutable) glob->makeConst(); cs->leaveGlobalInitFunction(rest); cs->valueMap[this] = CGResult(glob); return CGResult(glob); } else { fir::Value* val = 0; if(this->init) { val = this->init->codegen(cs, this->type).value; val = cs->oneWayAutocast(val, this->type); } else { val = cs->getDefaultValue(this->type); val = checkStore(val); } auto alloc = cs->irb.CreateLValue(this->type, this->id.name); cs->autoAssignRefCountedValue(alloc, val, /* isInitial: */ true); if(this->immutable) alloc->makeConst(); cs->addVariableUsingStorage(this, alloc); return CGResult(alloc); } } void cgn::CodegenState::addVariableUsingStorage(sst::VarDefn* var, fir::Value* alloc) { iceAssert(alloc); this->valueMap[var] = CGResult(alloc); this->addRAIIOrRCValueIfNecessary(alloc, /* type override: */ var->type); } CGResult sst::VarRef::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); fir::Value* value = 0; { auto it = cs->valueMap.find(this->def); if(it != cs->valueMap.end()) { value = it->second.value; } else { if(this->isImplicitField) { iceAssert(cs->isInMethodBody()); return cs->getStructFieldImplicitly(this->name); } else { this->def->codegen(cs); it = cs->valueMap.find(this->def); if(it == cs->valueMap.end()) { SimpleError::make(this->loc, "failed to codegen variable definition for '%s'", this->name) ->append(SimpleError::make(MsgType::Note, this->def->loc, "offending definition is here:")) ->postAndQuit(); } value = it->second.value; } } } // make sure types match... should we bother? if(value->getType() != this->type) error(this, "type mismatch; typechecking found type '%s', codegen gave type '%s'", this->type, value->getType()); return CGResult(value); } CGResult sst::SelfVarRef::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); iceAssert(cs->isInMethodBody()); return CGResult(cs->getMethodSelf()); } ================================================ FILE: source/fir/ConstantValue.cpp ================================================ // ConstantValue.cpp // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #include #include #include #include #include "ir/value.h" #include "ir/constant.h" namespace fir { ConstantValue::ConstantValue(Type* t) : Value(t) { this->kind = Kind::prvalue; } ConstantValue* ConstantValue::getZeroValue(Type* type) { iceAssert(!type->isVoidType() && "cannot make void constant"); return new ConstantValue(type); } ConstantValue* ConstantValue::getNull() { auto ret = new ConstantValue(fir::Type::getNull()); return ret; } std::string ConstantValue::str() { return ""; } ConstantBool* ConstantBool::get(bool val) { return new ConstantBool(val); } ConstantBool::ConstantBool(bool v) : ConstantValue(fir::Type::getBool()), value(v) { } bool ConstantBool::getValue() { return this->value; } std::string ConstantBool::str() { return this->value ? "true" : "false"; } ConstantBitcast* ConstantBitcast::get(ConstantValue* v, Type* t) { return new ConstantBitcast(v, t); } ConstantBitcast::ConstantBitcast(ConstantValue* v, Type* t) : ConstantValue(t), value(v) { } std::string ConstantBitcast::str() { return this->value->str(); } ConstantNumber* ConstantNumber::get(ConstantNumberType* cnt, const mpfr::mpreal& n) { return new ConstantNumber(cnt, n); } ConstantNumber::ConstantNumber(ConstantNumberType* cnt, const mpfr::mpreal& n) : ConstantValue(cnt) { this->number = n; } std::string ConstantNumber::str() { // 6 decimal places, like default printf. return this->number.toString("%.6R"); } // todo: unique these values. ConstantInt* ConstantInt::get(Type* intType, uint64_t val) { iceAssert(intType->isIntegerType() && "not integer type"); return new ConstantInt(intType, val); } ConstantInt::ConstantInt(Type* type, int64_t val) : ConstantValue(type) { this->value = val; } ConstantInt::ConstantInt(Type* type, uint64_t val) : ConstantValue(type) { this->value = val; } int64_t ConstantInt::getSignedValue() { return static_cast(this->value); } uint64_t ConstantInt::getUnsignedValue() { return this->value; } ConstantInt* ConstantInt::getInt8(int8_t value) { return ConstantInt::get(Type::getInt8(), value); } ConstantInt* ConstantInt::getInt16(int16_t value) { return ConstantInt::get(Type::getInt16(), value); } ConstantInt* ConstantInt::getInt32(int32_t value) { return ConstantInt::get(Type::getInt32(), value); } ConstantInt* ConstantInt::getInt64(int64_t value) { return ConstantInt::get(Type::getInt64(), value); } ConstantInt* ConstantInt::getUint8(uint8_t value) { return ConstantInt::get(Type::getUint8(), value); } ConstantInt* ConstantInt::getUint16(uint16_t value) { return ConstantInt::get(Type::getUint16(), value); } ConstantInt* ConstantInt::getUint32(uint32_t value) { return ConstantInt::get(Type::getUint32(), value); } ConstantInt* ConstantInt::getUint64(uint64_t value) { return ConstantInt::get(Type::getUint64(), value); } ConstantInt* ConstantInt::getNative(int64_t value) { return ConstantInt::get(Type::getNativeWord(), value); } ConstantInt* ConstantInt::getUNative(uint64_t value) { return ConstantInt::get(Type::getNativeUWord(), value); } std::string ConstantInt::str() { char buf[64] = {0}; if(this->getType() == Type::getInt8()) snprintf(buf, 63, "%" PRIi8, static_cast(this->value)); else if(this->getType() == Type::getInt16()) snprintf(buf, 63, "%" PRIi16, static_cast(this->value)); else if(this->getType() == Type::getInt32()) snprintf(buf, 63, "%" PRIi32, static_cast(this->value)); else if(this->getType() == Type::getInt64()) snprintf(buf, 63, "%" PRIi64, static_cast(this->value)); else if(this->getType() == Type::getUint8()) snprintf(buf, 63, "%" PRIu8, static_cast(this->value)); else if(this->getType() == Type::getUint16()) snprintf(buf, 63, "%" PRIu16, static_cast(this->value)); else if(this->getType() == Type::getUint32()) snprintf(buf, 63, "%" PRIu32, static_cast(this->value)); else if(this->getType() == Type::getUint64()) snprintf(buf, 63, "%" PRIu64, static_cast(this->value)); else snprintf(buf, 63, ""); return std::string(buf); } ConstantFP* ConstantFP::get(Type* type, float val) { iceAssert(type->isFloatingPointType() && "not floating point type"); return new ConstantFP(type, val); } ConstantFP* ConstantFP::get(Type* type, double val) { iceAssert(type->isFloatingPointType() && "not floating point type"); return new ConstantFP(type, val); } ConstantFP::ConstantFP(Type* type, float val) : fir::ConstantValue(type) { this->value = static_cast(val); } ConstantFP::ConstantFP(Type* type, double val) : fir::ConstantValue(type) { this->value = val; } double ConstantFP::getValue() { return this->value; } ConstantFP* ConstantFP::getFloat32(float value) { return ConstantFP::get(Type::getFloat32(), value); } ConstantFP* ConstantFP::getFloat64(double value) { return ConstantFP::get(Type::getFloat64(), value); } std::string ConstantFP::str() { char buf[64] = {0}; if(this->getType() == Type::getFloat32()) snprintf(buf, 63, "%.6f", static_cast(this->value)); else if(this->getType() == Type::getFloat64()) snprintf(buf, 63, "%.6f", static_cast(this->value)); else snprintf(buf, 63, ""); return std::string(buf); } ConstantStruct* ConstantStruct::get(StructType* st, const std::vector& members) { return new ConstantStruct(st, members); } ConstantStruct::ConstantStruct(StructType* st, const std::vector& members) : ConstantValue(st) { if(st->getElementCount() != members.size()) error("mismatched structs: expected %d fields, got %d", st->getElementCount(), members.size()); for(size_t i = 0; i < st->getElementCount(); i++) { if(st->getElementN(i) != members[i]->getType()) { error("mismatched types in field %d: expected '%s', got '%s'", i, st->getElementN(i), members[i]->getType()); } } // ok this->members = members; } std::string ConstantStruct::str() { auto sty = this->getType()->toStructType(); util::hash_map names; for(const auto& p : sty->getIndexMap()) names[p.second] = p.first; std::string ret = this->getType()->str() + " {\n"; for(size_t i = 0; i < sty->getElementCount(); i++) { auto v = this->members[i]->str(); auto t = sty->getElementN(i); auto n = names[i]; ret += zpr::sprint(" %s: %s = %s\n", n, t, v); } return ret + "}"; } ConstantCharSlice* ConstantCharSlice::get(const std::string& s) { return new ConstantCharSlice(s); } ConstantCharSlice::ConstantCharSlice(const std::string& s) : ConstantValue(fir::Type::getCharSlice(false)) { this->value = s; } std::string ConstantCharSlice::getValue() { return this->value; } std::string ConstantCharSlice::str() { return zpr::sprint("\"%s\"", this->value); } ConstantTuple* ConstantTuple::get(const std::vector& mems) { return new ConstantTuple(mems); } std::vector ConstantTuple::getValues() { return this->values; } static std::vector mapTypes(const std::vector& vs) { std::vector ret; ret.reserve(vs.size()); for(auto v : vs) ret.push_back(v->getType()); return ret; } // well this is stupid. ConstantTuple::ConstantTuple(const std::vector& mems) : fir::ConstantValue(fir::TupleType::get(mapTypes(mems))) { this->values = mems; } std::string ConstantTuple::str() { return "(" + zfu::join(zfu::map(this->values, [](auto x) -> auto { return x->str(); }), ", ") + ")"; } ConstantEnumCase* ConstantEnumCase::get(EnumType* et, ConstantInt* index, ConstantValue* value) { return new ConstantEnumCase(et, index, value); } ConstantInt* ConstantEnumCase::getIndex() { return this->index; } ConstantValue* ConstantEnumCase::getValue() { return this->value; } // well this is stupid. ConstantEnumCase::ConstantEnumCase(EnumType* et, ConstantInt* index, ConstantValue* value) : fir::ConstantValue(et) { this->index = index; this->value = value; } std::string ConstantEnumCase::str() { // TODO: why the fuck did i design enums this way?! return this->value->str(); } ConstantArray* ConstantArray::get(Type* type, const std::vector& vals) { return new ConstantArray(type, vals); } ConstantArray::ConstantArray(Type* type, const std::vector& vals) : fir::ConstantValue(type) { this->values = vals; } std::string ConstantArray::str() { return "[ " + zfu::join(zfu::map(this->values, [](auto x) -> auto { return x->str(); }), ", ") + " ]"; } ConstantDynamicArray* ConstantDynamicArray::get(DynamicArrayType* t, ConstantValue* d, ConstantValue* l, ConstantValue* c) { auto cda = new ConstantDynamicArray(t); cda->data = d; cda->length = l; cda->capacity = c; return cda; } ConstantDynamicArray* ConstantDynamicArray::get(ConstantArray* arr) { auto cda = new ConstantDynamicArray(DynamicArrayType::get(arr->getType()->toArrayType()->getElementType())); cda->arr = arr; return cda; } ConstantDynamicArray::ConstantDynamicArray(DynamicArrayType* t) : ConstantValue(t) { } std::string ConstantDynamicArray::str() { return ""; } ConstantDynamicString* ConstantDynamicString::get(const std::string& s) { return new ConstantDynamicString(s); } ConstantDynamicString::ConstantDynamicString(const std::string& s) : ConstantValue(fir::Type::getString()) { this->value = s; } std::string ConstantDynamicString::getValue() { return this->value; } std::string ConstantDynamicString::str() { return zpr::sprint("\"%s\"", this->value); } ConstantArraySlice* ConstantArraySlice::get(ArraySliceType* t, ConstantValue* d, ConstantValue* l) { auto cda = new ConstantArraySlice(t); cda->data = d; cda->length = l; return cda; } ConstantArraySlice::ConstantArraySlice(ArraySliceType* t) : ConstantValue(t) { } std::string ConstantArraySlice::str() { return ""; } } ================================================ FILE: source/fir/Function.cpp ================================================ // Function.cpp // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #include "ir/module.h" #include "ir/function.h" #include namespace fir { // argument stuff Argument::Argument(Function* fn, Type* type) : Value(type) { this->parentFunction = fn; this->realValue = new Value(type); } Argument::~Argument() { delete this->realValue; } Value* Argument::getActualValue() { if(this->realValue) return this->realValue; error("calling getActualValue() when not in function! (no real value)"); } Function* Argument::getParentFunction() { iceAssert(this->parentFunction); return this->parentFunction; } void Argument::setValue(Value* v) { iceAssert(v); this->realValue = v; } void Argument::clearValue() { this->realValue = 0; } // function stuff Function::Function(const Name& name, FunctionType* fnType, Module* module, LinkageType linkage) : GlobalValue(module, fnType, linkage) { this->ident = name; this->valueType = fnType; for(auto t : fnType->getArgumentTypes()) this->fnArguments.push_back(new Argument(this, t)); } Type* Function::getReturnType() { return this->getType()->getReturnType(); } size_t Function::getArgumentCount() { return this->fnArguments.size(); } const std::vector& Function::getArguments() { return this->fnArguments; } Argument* Function::getArgumentWithName(std::string name) { for(auto a : this->fnArguments) { if(a->getName().name == name) return a; } error("no argument named '%s' in function '%s'", name, this->getName().name); } bool Function::isCStyleVarArg() { return this->getType()->isCStyleVarArg(); } bool Function::isVariadic() { return this->getType()->isVariadicFunc(); } std::vector& Function::getBlockList() { return this->blocks; } void Function::deleteBody() { this->blocks.clear(); } bool Function::isIntrinsicFunction() { return this->fnIsIntrinsicFunction; } void Function::setIsIntrinsic() { this->fnIsIntrinsicFunction = true; } void Function::addStackAllocation(Type* ty) { this->stackAllocs.push_back(ty); } const std::vector& Function::getStackAllocations() { return this->stackAllocs; } void Function::cullUnusedValues() { } bool Function::wasDeclaredWithBodyElsewhere() { return this->hadBodyElsewhere; } void Function::setHadBodyElsewhere() { this->hadBodyElsewhere = true; } bool Function::isAlwaysInlined() { return this->alwaysInlined; } void Function::setAlwaysInline() { this->alwaysInlined = true; } Function* Function::create(const Name& name, fir::FunctionType* fnType, fir::Module* module, fir::LinkageType linkage) { return new Function(name, fnType, module, linkage); } // overridden stuff FunctionType* Function::getType() { FunctionType* ft = dcast(FunctionType, this->valueType); iceAssert(ft && "function is impostor (not valid function type)"); return ft; } } ================================================ FILE: source/fir/GlobalValue.cpp ================================================ // GlobalValue.cpp // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #include "ir/value.h" #include "ir/module.h" #include "ir/constant.h" namespace fir { GlobalValue::GlobalValue(Module* m, Type* type, LinkageType linkage, bool mut) : ConstantValue(type) { this->linkageType = linkage; this->parentModule = m; //* not a typo; only variables deserve to be 'lvalue', global values (eg. functions) //* should just be rvalues. if(mut) this->kind = Kind::lvalue; else this->kind = Kind::prvalue; } std::string GlobalValue::str() { return ""; } GlobalVariable::GlobalVariable(const Name& name, Module* module, Type* type, bool immutable, LinkageType lt, ConstantValue* initValue) : GlobalValue(module, type, lt, !immutable) { this->ident = name; this->initValue = initValue; this->kind = Kind::lvalue; this->isconst = immutable; } void GlobalVariable::setInitialValue(ConstantValue* constVal) { if(constVal && constVal->getType() != this->getType()) error("storing value of '%s' in global var of type '%s'", constVal->getType(), this->getType()); this->initValue = constVal; } ConstantValue* GlobalVariable::getInitialValue() { return this->initValue; } std::string GlobalVariable::str() { return this->initValue->str(); } } ================================================ FILE: source/fir/IRBlock.cpp ================================================ // IRBlock.cpp // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #include "ir/function.h" #include "ir/block.h" namespace fir { IRBlock::IRBlock() : Value(Type::getVoid()) { this->parentFunction = 0; } IRBlock::IRBlock(Function* fn) : Value(Type::getVoid()) { this->parentFunction = fn; } void IRBlock::setFunction(Function* fn) { this->parentFunction = fn; } Function* IRBlock::getParentFunction() { return this->parentFunction; } void IRBlock::eraseFromParentFunction() { iceAssert(this->parentFunction && "no function"); std::vector& blist = this->parentFunction->getBlockList(); for(auto it = blist.begin(); it != blist.end(); it++) { if(*it == this) { blist.erase(it); return; } } iceAssert(0 && "not in function"); } std::vector& IRBlock::getInstructions() { return this->instructions; } bool IRBlock::isTerminated() { if(this->instructions.size() == 0) return false; auto last = this->instructions.back(); return last->opKind == OpKind::Branch_Cond || last->opKind == OpKind::Branch_UnCond || last->opKind == OpKind::Value_Return; } } ================================================ FILE: source/fir/IRBuilder.cpp ================================================ // IRBuilder.cpp // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #include #include "ast.h" #include "gluecode.h" #include "ir/block.h" #include "ir/irbuilder.h" #include "ir/instruction.h" #include "memorypool.h" static bool isSAAType(fir::Type* t) { return t->isStringType() || t->isDynamicArrayType(); } static fir::Type* getSAAElmType(fir::Type* t) { iceAssert(isSAAType(t)); if(t->isStringType()) return fir::Type::getInt8(); else return t->getArrayElementType(); } namespace fir { IRBuilder::IRBuilder(Module* mod) { this->module = mod; this->currentBlock = 0; this->previousBlock = 0; this->currentFunction = 0; } void IRBuilder::setCurrentBlock(IRBlock* block) { this->previousBlock = this->currentBlock; this->currentBlock = block; if(this->currentBlock != 0) { if(this->currentBlock->parentFunction != 0) this->currentFunction = this->currentBlock->parentFunction; else this->currentFunction = 0; } else { this->currentFunction = 0; } } void IRBuilder::restorePreviousBlock() { this->currentBlock = this->previousBlock; } Function* IRBuilder::getCurrentFunction() { return this->currentFunction; } IRBlock* IRBuilder::getCurrentBlock() { return this->currentBlock; } static util::MemoryPool instr_pool; static Instruction* make_instr(OpKind kind, bool sideEffects, Type* out, const std::vector& vals, Value::Kind k = Value::Kind::prvalue) { return instr_pool.construct(kind, sideEffects, out, vals, k); } Value* IRBuilder::addInstruction(Instruction* instr, const std::string& vname) { iceAssert(this->currentBlock && "no current block"); // add instruction to the end of the block this->currentBlock->instructions.push_back(instr); Value* v = instr->realOutput; // v->addUser(this->currentBlock); v->setName(vname); return v; } static Instruction* getBinaryOpInstruction(const std::string& ao, Value* vlhs, Value* vrhs) { OpKind op = OpKind::Invalid; Type* lhs = vlhs->getType(); Type* rhs = vrhs->getType(); bool useFloating = (lhs->isFloatingPointType() || rhs->isFloatingPointType()); bool useSigned = ((lhs->isIntegerType() && lhs->toPrimitiveType()->isSigned()) || (rhs->isIntegerType() && rhs->toPrimitiveType()->isSigned())); PrimitiveType* lpt = lhs->toPrimitiveType(); PrimitiveType* rpt = rhs->toPrimitiveType(); iceAssert(lpt && rpt && "not primitive types"); Type* out = 0; if(ao == "+") { op = useFloating ? OpKind::Floating_Add : useSigned ? OpKind::Signed_Add : OpKind::Unsigned_Add; // use the larger type. if(useFloating) { if(lpt->getFloatingPointBitWidth() > rpt->getFloatingPointBitWidth()) out = lpt; else out = rpt; } else { // following c/c++ conventions, signed types are converted to unsigned types in mixed ops. if(lpt->getIntegerBitWidth() > rpt->getIntegerBitWidth()) { if(lpt->isSigned() && rpt->isSigned()) out = lpt; else out = (lpt->isSigned() ? rpt : lpt); } else { if(lpt->isSigned() && rpt->isSigned()) out = rpt; else out = (lpt->isSigned() ? rpt : lpt); } } } else if(ao == "-") { op = useFloating ? OpKind::Floating_Sub : useSigned ? OpKind::Signed_Sub : OpKind::Unsigned_Sub; // use the larger type. if(useFloating) { if(lpt->getFloatingPointBitWidth() > rpt->getFloatingPointBitWidth()) out = lpt; else out = rpt; } else { // following c/c++ conventions, signed types are converted to unsigned types in mixed ops. if(lpt->getIntegerBitWidth() > rpt->getIntegerBitWidth()) { if(lpt->isSigned() && rpt->isSigned()) out = lpt; else out = (lpt->isSigned() ? rpt : lpt); } else { if(lpt->isSigned() && rpt->isSigned()) out = rpt; else out = (lpt->isSigned() ? rpt : lpt); } } } else if(ao == "*") { op = useFloating ? OpKind::Floating_Mul : useSigned ? OpKind::Signed_Mul : OpKind::Unsigned_Mul; // use the larger type. if(useFloating) { if(lpt->getFloatingPointBitWidth() > rpt->getFloatingPointBitWidth()) out = lpt; else out = rpt; } else { // following c/c++ conventions, signed types are converted to unsigned types in mixed ops. if(lpt->getIntegerBitWidth() > rpt->getIntegerBitWidth()) { if(lpt->isSigned() && rpt->isSigned()) out = lpt; else out = (lpt->isSigned() ? rpt : lpt); } else { if(lpt->isSigned() && rpt->isSigned()) out = rpt; else out = (lpt->isSigned() ? rpt : lpt); } } } else if(ao == "/") { op = useFloating ? OpKind::Floating_Div : useSigned ? OpKind::Signed_Div : OpKind::Unsigned_Div; // use the larger type. if(useFloating) { if(lpt->getFloatingPointBitWidth() > rpt->getFloatingPointBitWidth()) out = lpt; else out = rpt; } else { // following c/c++ conventions, signed types are converted to unsigned types in mixed ops. if(lpt->getIntegerBitWidth() > rpt->getIntegerBitWidth()) { if(lpt->isSigned() && rpt->isSigned()) out = lpt; else out = (lpt->isSigned() ? rpt : lpt); } else { if(lpt->isSigned() && rpt->isSigned()) out = rpt; else out = (lpt->isSigned() ? rpt : lpt); } } } else if(ao == "%") { op = useFloating ? OpKind::Floating_Mod : useSigned ? OpKind::Signed_Mod : OpKind::Unsigned_Mod; // use the larger type. if(useFloating) { if(lpt->getFloatingPointBitWidth() > rpt->getFloatingPointBitWidth()) out = lpt; else out = rpt; } else { // following c/c++ conventions, signed types are converted to unsigned types in mixed ops. if(lpt->getIntegerBitWidth() > rpt->getIntegerBitWidth()) { if(lpt->isSigned() && rpt->isSigned()) out = lpt; else out = (lpt->isSigned() ? rpt : lpt); } else { if(lpt->isSigned() && rpt->isSigned()) out = rpt; else out = (lpt->isSigned() ? rpt : lpt); } } } else if(ao == "<<") { if(useFloating) iceAssert("shift operation can only be done with ints"); op = OpKind::Bitwise_Shl; out = lhs; } else if(ao == ">>") { if(useFloating) iceAssert("shift operation can only be done with ints"); op = useSigned ? OpKind::Bitwise_Arithmetic_Shr : OpKind::Bitwise_Logical_Shr; out = lhs; } else if(ao == "&") { if(useFloating) iceAssert("bitwise ops only defined for int types (cast if needed)"); op = OpKind::Bitwise_And; out = lhs; } else if(ao == "|") { if(useFloating) iceAssert("bitwise ops only defined for int types (cast if needed)"); op = OpKind::Bitwise_Or; out = lhs; } else if(ao == "^") { if(useFloating) iceAssert("bitwise ops only defined for int types (cast if needed)"); op = OpKind::Bitwise_Xor; out = lhs; } else if(ao == "~") { if(useFloating) iceAssert("bitwise ops only defined for int types (cast if needed)"); op = OpKind::Bitwise_Not; out = lhs; } else { return 0; } return make_instr(op, false, out, { vlhs, vrhs }); } Value* IRBuilder::BinaryOp(const std::string& ao, Value* a, Value* b, const std::string& vname) { Instruction* instr = getBinaryOpInstruction(ao, a, b); if(instr == 0) return 0; return this->addInstruction(instr, vname); } Value* IRBuilder::Negate(Value* a, const std::string& vname) { iceAssert(a->getType()->toPrimitiveType() && "cannot negate non-primitive type"); iceAssert((a->getType()->isFloatingPointType() || a->getType()->toPrimitiveType()->isSigned()) && "cannot negate unsigned type"); Instruction* instr = make_instr(a->getType()->isFloatingPointType() ? OpKind::Floating_Neg : OpKind::Signed_Neg, false, a->getType(), { a }); return this->addInstruction(instr, vname); } Value* IRBuilder::Add(Value* a, Value* b, const std::string& vname) { if(a->getType() != b->getType()) error("irbuilder: creating add instruction with non-equal types ('%s' vs '%s')", a->getType(), b->getType()); OpKind ok = OpKind::Invalid; if(a->getType()->isSignedIntType()) ok = OpKind::Signed_Add; else if(a->getType()->isIntegerType()) ok = OpKind::Unsigned_Add; else ok = OpKind::Floating_Add; Instruction* instr = make_instr(ok, false, a->getType(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::Subtract(Value* a, Value* b, const std::string& vname) { if(a->getType() != b->getType()) error("irbuilder: creating sub instruction with non-equal types ('%s' vs '%s')", a->getType(), b->getType()); OpKind ok = OpKind::Invalid; if(a->getType()->isSignedIntType()) ok = OpKind::Signed_Sub; else if(a->getType()->isIntegerType()) ok = OpKind::Unsigned_Sub; else ok = OpKind::Floating_Sub; Instruction* instr = make_instr(ok, false, a->getType(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::Multiply(Value* a, Value* b, const std::string& vname) { if(a->getType() != b->getType()) error("irbuilder: creating mul instruction with non-equal types ('%s' vs '%s')", a->getType(), b->getType()); OpKind ok = OpKind::Invalid; if(a->getType()->isSignedIntType()) ok = OpKind::Signed_Mul; else if(a->getType()->isIntegerType()) ok = OpKind::Unsigned_Mul; else ok = OpKind::Floating_Mul; Instruction* instr = make_instr(ok, false, a->getType(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::Divide(Value* a, Value* b, const std::string& vname) { if(a->getType() != b->getType()) error("irbuilder: creating div instruction with non-equal types ('%s' vs '%s')", a->getType(), b->getType()); OpKind ok = OpKind::Invalid; if(a->getType()->isSignedIntType()) ok = OpKind::Signed_Div; else if(a->getType()->isIntegerType()) ok = OpKind::Unsigned_Div; else ok = OpKind::Floating_Div; Instruction* instr = make_instr(ok, false, a->getType(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::Modulo(Value* a, Value* b, const std::string& vname) { if(a->getType() != b->getType()) error("irbuilder: creating mod instruction with non-equal types ('%s' vs '%s')", a->getType(), b->getType()); OpKind ok = OpKind::Invalid; if(a->getType()->isSignedIntType()) ok = OpKind::Signed_Mod; else if(a->getType()->isIntegerType()) ok = OpKind::Unsigned_Mod; else ok = OpKind::Floating_Mod; Instruction* instr = make_instr(ok, false, a->getType(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::FTruncate(Value* v, Type* targetType, const std::string& vname) { iceAssert(v->getType()->isFloatingPointType() && targetType->isFloatingPointType() && "not floating point type"); Instruction* instr = make_instr(OpKind::Floating_Truncate, false, targetType, zfu::vectorOf(v, ConstantValue::getZeroValue(targetType)) ); return this->addInstruction(instr, vname); } Value* IRBuilder::FExtend(Value* v, Type* targetType, const std::string& vname) { iceAssert(v->getType()->isFloatingPointType() && targetType->isFloatingPointType() && "not floating point type"); Instruction* instr = make_instr(OpKind::Floating_Extend, false, targetType, { v, ConstantValue::getZeroValue(targetType) }); return this->addInstruction(instr, vname); } Value* IRBuilder::ICmpEQ(Value* a, Value* b, const std::string& vname) { //* note: allows comparing mutable and immutable pointers. if(a->getType() != b->getType() && !(a->getType()->isPointerType() && b->getType()->isPointerType() && a->getType()->getPointerElementType() == b->getType()->getPointerElementType())) { error("irbuilder: creating icmp eq instruction with non-equal types"); } Instruction* instr = make_instr(OpKind::ICompare_Equal, false, Type::getBool(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::ICmpNEQ(Value* a, Value* b, const std::string& vname) { //* note: allows comparing mutable and immutable pointers. if(a->getType() != b->getType() && !(a->getType()->isPointerType() && b->getType()->isPointerType() && a->getType()->getPointerElementType() == b->getType()->getPointerElementType())) { error("irbuilder: creating icmp neq instruction with non-equal types"); } Instruction* instr = make_instr(OpKind::ICompare_NotEqual, false, Type::getBool(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::ICmpGT(Value* a, Value* b, const std::string& vname) { //* note: allows comparing mutable and immutable pointers. if(a->getType() != b->getType() && !(a->getType()->isPointerType() && b->getType()->isPointerType() && a->getType()->getPointerElementType() == b->getType()->getPointerElementType())) { error("irbuilder: creating icmp gt instruction with non-equal types"); } Instruction* instr = make_instr(OpKind::ICompare_Greater, false, Type::getBool(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::ICmpLT(Value* a, Value* b, const std::string& vname) { //* note: allows comparing mutable and immutable pointers. if(a->getType() != b->getType() && !(a->getType()->isPointerType() && b->getType()->isPointerType() && a->getType()->getPointerElementType() == b->getType()->getPointerElementType())) { error("irbuilder: creating icmp lt instruction with non-equal types"); } Instruction* instr = make_instr(OpKind::ICompare_Less, false, Type::getBool(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::ICmpGEQ(Value* a, Value* b, const std::string& vname) { //* note: allows comparing mutable and immutable pointers. if(a->getType() != b->getType() && !(a->getType()->isPointerType() && b->getType()->isPointerType() && a->getType()->getPointerElementType() == b->getType()->getPointerElementType())) { error("irbuilder: creating icmp geq instruction with non-equal types"); } Instruction* instr = make_instr(OpKind::ICompare_GreaterEqual, false, Type::getBool(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::ICmpLEQ(Value* a, Value* b, const std::string& vname) { //* note: allows comparing mutable and immutable pointers. if(a->getType() != b->getType() && !(a->getType()->isPointerType() && b->getType()->isPointerType() && a->getType()->getPointerElementType() == b->getType()->getPointerElementType())) { error("irbuilder: creating icmp leq instruction with non-equal types"); } Instruction* instr = make_instr(OpKind::ICompare_LessEqual, false, Type::getBool(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::FCmpEQ_ORD(Value* a, Value* b, const std::string& vname) { iceAssert(a->getType() == b->getType() && "creating cmp eq_ord instruction with non-equal types"); iceAssert(a->getType()->isFloatingPointType() && "creating fcmp instruction with non floating-point types"); Instruction* instr = make_instr(OpKind::FCompare_Equal_ORD, false, Type::getBool(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::FCmpEQ_UNORD(Value* a, Value* b, const std::string& vname) { iceAssert(a->getType() == b->getType() && "creating cmp eq_uord instruction with non-equal types"); iceAssert(a->getType()->isFloatingPointType() && "creating fcmp instruction with non floating-point types"); Instruction* instr = make_instr(OpKind::FCompare_Equal_UNORD, false, Type::getBool(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::FCmpNEQ_ORD(Value* a, Value* b, const std::string& vname) { iceAssert(a->getType() == b->getType() && "creating cmp neq_ord instruction with non-equal types"); iceAssert(a->getType()->isFloatingPointType() && "creating fcmp instruction with non floating-point types"); Instruction* instr = make_instr(OpKind::FCompare_NotEqual_ORD, false, Type::getBool(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::FCmpNEQ_UNORD(Value* a, Value* b, const std::string& vname) { iceAssert(a->getType() == b->getType() && "creating cmp neq_uord instruction with non-equal types"); iceAssert(a->getType()->isFloatingPointType() && "creating fcmp instruction with non floating-point types"); Instruction* instr = make_instr(OpKind::FCompare_NotEqual_UNORD, false, Type::getBool(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::FCmpGT_ORD(Value* a, Value* b, const std::string& vname) { iceAssert(a->getType() == b->getType() && "creating cmp gt instruction with non-equal types"); iceAssert(a->getType()->isFloatingPointType() && "creating fcmp instruction with non floating-point types"); Instruction* instr = make_instr(OpKind::FCompare_Greater_ORD, false, Type::getBool(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::FCmpGT_UNORD(Value* a, Value* b, const std::string& vname) { iceAssert(a->getType() == b->getType() && "creating cmp gt instruction with non-equal types"); iceAssert(a->getType()->isFloatingPointType() && "creating fcmp instruction with non floating-point types"); Instruction* instr = make_instr(OpKind::FCompare_Greater_UNORD, false, Type::getBool(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::FCmpLT_ORD(Value* a, Value* b, const std::string& vname) { iceAssert(a->getType() == b->getType() && "creating cmp lt instruction with non-equal types"); iceAssert(a->getType()->isFloatingPointType() && "creating fcmp instruction with non floating-point types"); Instruction* instr = make_instr(OpKind::FCompare_Less_ORD, false, Type::getBool(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::FCmpLT_UNORD(Value* a, Value* b, const std::string& vname) { iceAssert(a->getType() == b->getType() && "creating cmp lt instruction with non-equal types"); iceAssert(a->getType()->isFloatingPointType() && "creating fcmp instruction with non floating-point types"); Instruction* instr = make_instr(OpKind::FCompare_Less_UNORD, false, Type::getBool(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::FCmpGEQ_ORD(Value* a, Value* b, const std::string& vname) { iceAssert(a->getType() == b->getType() && "creating cmp geq instruction with non-equal types"); iceAssert(a->getType()->isFloatingPointType() && "creating fcmp instruction with non floating-point types"); Instruction* instr = make_instr(OpKind::FCompare_GreaterEqual_ORD, false, Type::getBool(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::FCmpGEQ_UNORD(Value* a, Value* b, const std::string& vname) { iceAssert(a->getType() == b->getType() && "creating cmp geq instruction with non-equal types"); iceAssert(a->getType()->isFloatingPointType() && "creating fcmp instruction with non floating-point types"); Instruction* instr = make_instr(OpKind::FCompare_GreaterEqual_UNORD, false, Type::getBool(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::FCmpLEQ_ORD(Value* a, Value* b, const std::string& vname) { iceAssert(a->getType() == b->getType() && "creating cmp leq instruction with non-equal types"); iceAssert(a->getType()->isFloatingPointType() && "creating fcmp instruction with non floating-point types"); Instruction* instr = make_instr(OpKind::FCompare_LessEqual_ORD, false, Type::getBool(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::FCmpLEQ_UNORD(Value* a, Value* b, const std::string& vname) { iceAssert(a->getType() == b->getType() && "creating cmp leq instruction with non-equal types"); iceAssert(a->getType()->isFloatingPointType() && "creating fcmp instruction with non floating-point types"); Instruction* instr = make_instr(OpKind::FCompare_LessEqual_UNORD, false, Type::getBool(), { a, b }); return this->addInstruction(instr, vname); } // returns -1 for a < b, 0 for a == b, 1 for a > b Value* IRBuilder::ICmpMulti(Value* a, Value* b, const std::string& vname) { iceAssert(a->getType() == b->getType() && "creating icmp multi instruction with non-equal types"); // iceAssert(a->getType()->isIntegerType() && "creating icmp multi instruction with non-integer type"); Instruction* instr = make_instr(OpKind::ICompare_Multi, false, Type::getNativeWord(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::FCmpMulti(Value* a, Value* b, const std::string& vname) { iceAssert(a->getType() == b->getType() && "creating cmp leq instruction with non-equal types"); iceAssert(a->getType()->isFloatingPointType() && "creating fcmp instruction with non floating-point types"); Instruction* instr = make_instr(OpKind::FCompare_Multi, false, Type::getNativeWord(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::BitwiseXOR(Value* a, Value* b, const std::string& vname) { iceAssert(a->getType() == b->getType() && "creating bitwise xor instruction with non-equal types"); Instruction* instr = make_instr(OpKind::Bitwise_Xor, false, a->getType(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::BitwiseLogicalSHR(Value* a, Value* b, const std::string& vname) { iceAssert(a->getType() == b->getType() && "creating bitwise lshl instruction with non-equal types"); Instruction* instr = make_instr(OpKind::Bitwise_Logical_Shr, false, a->getType(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::BitwiseArithmeticSHR(Value* a, Value* b, const std::string& vname) { iceAssert(a->getType() == b->getType() && "creating bitwise ashl instruction with non-equal types"); Instruction* instr = make_instr(OpKind::Bitwise_Arithmetic_Shr, false, a->getType(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::BitwiseSHL(Value* a, Value* b, const std::string& vname) { iceAssert(a->getType() == b->getType() && "creating bitwise shr instruction with non-equal types"); Instruction* instr = make_instr(OpKind::Bitwise_Shl, false, a->getType(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::BitwiseAND(Value* a, Value* b, const std::string& vname) { iceAssert(a->getType() == b->getType() && "creating bitwise and instruction with non-equal types"); Instruction* instr = make_instr(OpKind::Bitwise_And, false, a->getType(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::BitwiseOR(Value* a, Value* b, const std::string& vname) { iceAssert(a->getType() == b->getType() && "creating bitwise or instruction with non-equal types"); Instruction* instr = make_instr(OpKind::Bitwise_Or, false, a->getType(), { a, b }); return this->addInstruction(instr, vname); } Value* IRBuilder::BitwiseNOT(Value* a, const std::string& vname) { Instruction* instr = make_instr(OpKind::Bitwise_Not, false, a->getType(), { a }); return this->addInstruction(instr, vname); } Value* IRBuilder::Bitcast(Value* v, Type* targetType, const std::string& vname) { Instruction* instr = make_instr(OpKind::Cast_Bitcast, false, targetType, { v, ConstantValue::getZeroValue(targetType) }); return this->addInstruction(instr, vname); } Value* IRBuilder::IntSizeCast(Value* v, Type* targetType, const std::string& vname) { iceAssert((v->getType()->isIntegerType() || v->getType()->isBoolType()) && "value is not integer type"); iceAssert((targetType->isIntegerType() || targetType->isBoolType()) && "target is not integer type"); // make constant result for constant operand if(ConstantInt* ci = dcast(ConstantInt, v)) { return ConstantInt::get(targetType, ci->getSignedValue()); } Instruction* instr = make_instr(OpKind::Cast_IntSize, false, targetType, { v, ConstantValue::getZeroValue(targetType) }); return this->addInstruction(instr, vname); } Value* IRBuilder::IntSignednessCast(Value* v, Type* targetType, const std::string& vname) { iceAssert(v->getType()->isIntegerType() && "value is not integer type"); iceAssert(targetType->isIntegerType() && "target is not integer type"); // make constant result for constant operand if(ConstantInt* ci = dcast(ConstantInt, v)) { if(ci->getType()->isSignedIntType()) return ConstantInt::get(targetType, ci->getSignedValue()); else return ConstantInt::get(targetType, ci->getUnsignedValue()); } Instruction* instr = make_instr(OpKind::Cast_IntSignedness, false, targetType, { v, ConstantValue::getZeroValue(targetType) }); return this->addInstruction(instr, vname); } Value* IRBuilder::FloatToIntCast(Value* v, Type* targetType, const std::string& vname) { iceAssert(v->getType()->isFloatingPointType() && "value is not floating point type"); iceAssert(targetType->isIntegerType() && "target is not integer type"); // make constant result for constant operand if(ConstantFP* cfp = dcast(ConstantFP, v)) { double _ = 0; if(std::modf(cfp->getValue(), &_) != 0.0) warn("truncating constant '%f' in constant cast to type '%s'", cfp->getValue(), targetType); return ConstantInt::get(targetType, static_cast(cfp->getValue())); } Instruction* instr = make_instr(OpKind::Cast_FloatToInt, false, targetType, { v, ConstantValue::getZeroValue(targetType) }); return this->addInstruction(instr, vname); } Value* IRBuilder::IntToFloatCast(Value* v, Type* targetType, const std::string& vname) { iceAssert(v->getType()->isIntegerType() && "value is not integer type"); iceAssert(targetType->isFloatingPointType() && "target is not floating point type"); // make constant result for constant operand if(ConstantInt* ci = dcast(ConstantInt, v)) { ConstantFP* ret = 0; bool sgn = ci->getType()->isSignedIntType(); if(targetType == Type::getFloat32()) { if(sgn) ret = ConstantFP::getFloat32(static_cast(ci->getSignedValue())); else ret = ConstantFP::getFloat32(static_cast(ci->getUnsignedValue())); } else if(targetType == Type::getFloat64()) { if(sgn) ret = ConstantFP::getFloat64(static_cast(ci->getSignedValue())); else ret = ConstantFP::getFloat64(static_cast(ci->getUnsignedValue())); } else { error("irbuilder: unknown floating point type '%s'", targetType); } return ret; } Instruction* instr = make_instr(OpKind::Cast_IntToFloat, false, targetType, { v, ConstantValue::getZeroValue(targetType) }); return this->addInstruction(instr, vname); } Value* IRBuilder::PointerTypeCast(Value* v, Type* targetType, const std::string& vname) { iceAssert((v->getType()->isPointerType() || v->getType()->isNullType()) && "value is not pointer type"); iceAssert((targetType->isPointerType() || targetType->isNullType()) && "target is not pointer type"); Instruction* instr = make_instr(OpKind::Cast_PointerType, false, targetType, { v, ConstantValue::getZeroValue(targetType) }); return this->addInstruction(instr, vname); } Value* IRBuilder::PointerToIntCast(Value* v, Type* targetType, const std::string& vname) { iceAssert(v->getType()->isPointerType() && "value is not pointer type"); iceAssert(targetType->isIntegerType() && "target is not integer type"); Instruction* instr = make_instr(OpKind::Cast_PointerToInt, false, targetType, { v, ConstantValue::getZeroValue(targetType) }); return this->addInstruction(instr, vname); } Value* IRBuilder::IntToPointerCast(Value* v, Type* targetType, const std::string& vname) { iceAssert(v->getType()->isIntegerType() && "value is not integer type"); iceAssert(targetType->isPointerType() && "target is not pointer type"); Instruction* instr = make_instr(OpKind::Cast_IntToPointer, false, targetType, { v, ConstantValue::getZeroValue(targetType) }); return this->addInstruction(instr, vname); } Value* IRBuilder::IntTruncate(Value* v, Type* targetType, const std::string& vname) { iceAssert(v->getType()->isIntegerType() && "value is not integer type"); iceAssert(targetType->isIntegerType() && "target is not integer type"); Instruction* instr = make_instr(OpKind::Integer_Truncate, false, targetType, { v, ConstantValue::getZeroValue(targetType) }); return this->addInstruction(instr, vname); } Value* IRBuilder::IntZeroExt(Value* v, Type* targetType, const std::string& vname) { iceAssert((v->getType()->isIntegerType() || v->getType()->isBoolType()) && "value is not integer type"); iceAssert(targetType->isIntegerType() && "target is not integer type"); Instruction* instr = make_instr(OpKind::Integer_ZeroExt, false, targetType, { v, ConstantValue::getZeroValue(targetType) }); return this->addInstruction(instr, vname); } Value* IRBuilder::AppropriateCast(Value* v, Type* r, const std::string& vname) { auto l = v->getType(); if(l->isIntegerType() && r->isIntegerType()) return this->IntSizeCast(v, r, vname); else if(l->isFloatingPointType() && r->isFloatingPointType()) return (l->getBitWidth() > r->getBitWidth() ? this->FTruncate(v, r, vname) : this->FExtend(v, r, vname)); else if(l->isIntegerType() && r->isFloatingPointType()) return this->IntToFloatCast(v, r, vname); else if(l->isFloatingPointType() && r->isIntegerType()) return this->FloatToIntCast(v, r, vname); else if(l->isIntegerType() && r->isPointerType()) return this->IntToPointerCast(v, r, vname); else if(l->isPointerType() && r->isIntegerType()) return this->PointerToIntCast(v, r, vname); else if(l->isPointerType() && r->isPointerType()) return this->PointerTypeCast(v, r, vname); // nope. return 0; } Value* IRBuilder::Call(Function* fn, const std::string& vname) { return this->Call(fn, { }, vname); } Value* IRBuilder::Call(Function* fn, Value* p1, const std::string& vname) { return this->Call(fn, { p1 }, vname); } Value* IRBuilder::Call(Function* fn, Value* p1, Value* p2, const std::string& vname) { return this->Call(fn, { p1, p2 }, vname); } Value* IRBuilder::Call(Function* fn, Value* p1, Value* p2, Value* p3, const std::string& vname) { return this->Call(fn, { p1, p2, p3 }, vname); } Value* IRBuilder::Call(Function* fn, Value* p1, Value* p2, Value* p3, Value* p4, const std::string& vname) { return this->Call(fn, { p1, p2, p3, p4 }, vname); } Value* IRBuilder::Call(Function* fn, const std::vector& args, const std::string& vname) { if(args.size() != fn->getArgumentCount() && !fn->isVariadic() && !fn->isCStyleVarArg()) { error("irbuilder: calling function '%s' with the wrong number of arguments (needs %d, have %d)", fn->getName().str(), fn->getArgumentCount(), args.size()); } auto autocastStuff = [this](Value* arg, Type* target) -> Value* { auto isSlice = [](Type* ty) -> bool { return ty->isArraySliceType(); }; auto isVariadicSlice = [&isSlice](Type* ty) -> bool { return isSlice(ty) && ty->toArraySliceType()->isVariadicType(); }; auto getSliceElm = [](Type* ty) -> Type* { return ty->getArrayElementType(); }; auto isSliceMut = [&isSlice](Type* ty) -> bool { return isSlice(ty) && ty->toArraySliceType()->isMutable(); }; auto at = arg->getType(); if((isSlice(at) && isSlice(target) && (isVariadicSlice(at) != isVariadicSlice(target))) || (isSlice(at) && isSlice(target) && getSliceElm(at) == getSliceElm(target) && isSliceMut(at) && !isSliceMut(target) )) { // silently cast, because they're the same thing // the distinction is solely for the type system's benefit return this->Bitcast(arg, target); } else if(at->isPointerType() && target->isPointerType() && at->getPointerElementType() == target->getPointerElementType() && at->isMutablePointer() && target->isImmutablePointer()) { // this is ok. at the llvm level the cast should reduce to a no-op. return this->PointerTypeCast(arg, target); } else { return arg; } }; std::vector out; out.reserve(args.size()); bool forwarded = false; std::vector variadicArgs; auto numArgs = fn->getArgumentCount(); for(size_t i = 0; i < args.size(); i++) { auto at = args[i]->getType(); if(i < (fn->isVariadic() ? numArgs - 1 : numArgs)) { auto target = fn->getArguments()[i]->getType(); out.push_back(autocastStuff(args[i], target)); if(out[i]->getType() != target) { error("irbuilder: mismatch in argument type (arg. %d) in function '%s' (need '%s', have '%s')", i, fn->getName().str(), fn->getArguments()[i]->getType(), out[i]->getType()); } } else if(fn->isVariadic()) { iceAssert(fn->getArguments().back()->getType()->isVariadicArrayType()); auto elm = fn->getArguments().back()->getType()->getArrayElementType(); if(at->isArraySliceType() && at->getArrayElementType() == elm) { forwarded = true; out.push_back(args[i]); } else if(args[i]->getType() != elm) { error("irbuilder: mismatch in argument type (in variadic portion) (arg. %d) in function '%s' (need '%s', have '%s')", i, fn->getName().str(), elm, args[i]->getType()); } else { // handle it later, lol. variadicArgs.push_back(autocastStuff(args[i], elm)); } } else if(fn->isCStyleVarArg()) { // auto-convert strings and char slices into char* when passing to va_args if(at->isStringType()) out.push_back(this->GetSAAData(args[i])); else if(at->isCharSliceType()) out.push_back(this->GetArraySliceData(args[i])); else out.push_back(args[i]); } else { // shouldn't happen -- we should've errored out earlier. iceAssert(0); } } if(variadicArgs.size() > 0 && !forwarded) { iceAssert(fn->isVariadic()); iceAssert(fn->getArguments().back()->getType()->isVariadicArrayType()); auto elm = fn->getArguments().back()->getType()->getArrayElementType(); //? so the strat here is to stack-allocate an array, so we get a pointer to the array, //? with which we can use GEP instructions to store things inside. auto arrty = ArrayType::get(elm, variadicArgs.size()); auto arrptr = this->StackAlloc(arrty); for(size_t i = 0; i < variadicArgs.size(); i++) this->WritePtr(variadicArgs[i], this->ConstGEP2(arrptr, 0, i)); // then we make a slice out of it auto slcty = ArraySliceType::getVariadic(elm); auto slc = this->CreateValue(slcty); // ugh, fix mutability cast. slc = this->SetArraySliceData(slc, this->PointerTypeCast(this->ConstGEP2(arrptr, 0, 0), elm->getPointerTo())); slc = this->SetArraySliceLength(slc, ConstantInt::getNative(variadicArgs.size())); // ok, this is the last argument. out.push_back(slc); } else if(fn->isVariadic() && variadicArgs.empty() && !forwarded) { // ok, insert the empty slice here. auto elm = fn->getArguments().back()->getType()->getArrayElementType(); out.push_back(ConstantArraySlice::get(ArraySliceType::getVariadic(elm), ConstantValue::getZeroValue(elm->getPointerTo()), ConstantInt::getNative(0))); } out.insert(out.begin(), fn); Instruction* instr = make_instr(OpKind::Value_CallFunction, true, fn->getType()->getReturnType(), out); return this->addInstruction(instr, vname); } Value* IRBuilder::Call(Function* fn, const std::initializer_list& args, const std::string& vname) { return this->Call(fn, std::vector(args.begin(), args.end()), vname); } Value* IRBuilder::CallToFunctionPointer(Value* fn, FunctionType* ft, const std::vector& args, const std::string& vname) { //* note: we're using our operator overload here for T + VEC auto out = fn + args; Instruction* instr = make_instr(OpKind::Value_CallFunctionPointer, true, ft->getReturnType(), out); return this->addInstruction(instr, vname); } Value* IRBuilder::CallVirtualMethod(ClassType* cls, FunctionType* ft, size_t index, const std::vector& args, const std::string& vname) { // args[0] must be the self, for obvious reasons. auto ty = args[0]->getType(); iceAssert(ty->isPointerType() && ty->getPointerElementType()->isClassType()); auto self = ty->getPointerElementType()->toClassType(); iceAssert(self && self == cls); Instruction* instr = make_instr(OpKind::Value_CallVirtualMethod, true, ft->getReturnType(), zfu::vectorOf( ConstantValue::getZeroValue(cls), ConstantInt::getNative(index), ConstantValue::getZeroValue(ft) ) + args ); return this->addInstruction(instr, vname); } Value* IRBuilder::Return(Value* v) { Instruction* instr = make_instr(OpKind::Value_Return, true, Type::getVoid(), { v }); return this->addInstruction(instr, ""); } Value* IRBuilder::ReturnVoid() { Instruction* instr = make_instr(OpKind::Value_Return, true, Type::getVoid(), { }); return this->addInstruction(instr, ""); } Value* IRBuilder::LogicalNot(Value* v, const std::string& vname) { Instruction* instr = make_instr(OpKind::Logical_Not, false, Type::getBool(), { v }); return this->addInstruction(instr, vname); } PHINode* IRBuilder::CreatePHINode(Type* type, const std::string& vname) { Instruction* instr = make_instr(OpKind::Value_CreatePHI, false, type->getPointerTo(), { ConstantValue::getZeroValue(type) }); // we need to 'lift' (hoist) the allocation up to make it the first in the block // this is an llvm requirement. // MEMORY LEAK instr->realOutput = new PHINode(type); Value* ret = instr->realOutput; ret->setName(vname); // insert at the front (back = no guarantees) this->currentBlock->instructions.insert(this->currentBlock->instructions.begin(), instr); return dcast(PHINode, instr->realOutput); } Value* IRBuilder::StackAlloc(Type* type, const std::string& vname) { Instruction* instr = make_instr(OpKind::Value_StackAlloc, false, type->getMutablePointerTo(), { ConstantValue::getZeroValue(type) }); // we need to 'lift' (hoist) the allocation up to the entry block of the function // this prevents allocation inside loops eating stack memory forever Value* ret = instr->realOutput; ret->setName(vname); // get the parent function auto parent = this->currentBlock->getParentFunction(); iceAssert(parent); parent->addStackAllocation(type); // get the entry block auto entry = parent->getBlockList().front(); iceAssert(entry); // insert at the front (back = no guarantees) entry->instructions.insert(entry->instructions.begin(), instr); return ret; } Value* IRBuilder::ImmutStackAlloc(Type* type, Value* v, const std::string& vname) { Value* ret = this->StackAlloc(type, vname); this->WritePtr(v, ret); // now make it immutable. ret->setType(type->getPointerTo()); return ret; } Value* IRBuilder::CreateSliceFromSAA(Value* saa, bool mut, const std::string& vname) { if(!isSAAType(saa->getType())) error("irbuilder: expected string or dynamic array type, found '%s' instead", saa->getType()); auto slc = this->CreateValue(saa->getType()->isStringType() ? Type::getCharSlice(mut) : ArraySliceType::get(saa->getType()->getArrayElementType(), mut)); auto slcelmty = slc->getType()->getArrayElementType(); slc = this->SetArraySliceData(slc, this->PointerTypeCast(this->GetSAAData(saa), mut ? slcelmty->getMutablePointerTo() : slcelmty->getPointerTo())); slc = this->SetArraySliceLength(slc, this->GetSAALength(saa)); slc->setName(vname); return slc; } void IRBuilder::CondBranch(Value* condition, IRBlock* trueB, IRBlock* falseB) { Instruction* instr = make_instr(OpKind::Branch_Cond, true, Type::getVoid(), { condition, trueB, falseB }); this->addInstruction(instr, ""); } void IRBuilder::UnCondBranch(IRBlock* target) { Instruction* instr = make_instr(OpKind::Branch_UnCond, true, Type::getVoid(), { target }); this->addInstruction(instr, ""); } Value* IRBuilder::GetRawUnionFieldByType(Value* lval, Type* type, const std::string& vname) { if(!lval->islvalue()) error("irbuilder: cannot do raw union ops on non-lvalue"); if(!lval->getType()->isRawUnionType()) error("irbuilder: '%s' is not a raw union type!", lval->getType()); Instruction* instr = make_instr(OpKind::RawUnion_GEP, false, type, { lval, ConstantValue::getZeroValue(type) }); auto ret = this->addInstruction(instr, ""); ret->setKind(lval->kind); ret->setName(vname); return ret; } Value* IRBuilder::GetRawUnionField(Value* lval, const std::string& field, const std::string& vname) { if(!lval->islvalue()) error("irbuilder: cannot do raw union ops on non-lvalue"); if(!lval->getType()->isRawUnionType()) error("irbuilder: '%s' is not a raw union type!", lval->getType()); auto rut = lval->getType()->toRawUnionType(); if(!rut->hasVariant(field)) error("irbuilder: union '%s' does not have a field '%s'", rut->getTypeName(), field); auto ty = rut->getVariant(field); return this->GetRawUnionFieldByType(lval, ty, vname); } template static Instruction* doGEPOnCompoundType(T* type, Value* structPtr, size_t memberIndex) { if(!structPtr->islvalue()) error("irbuilder: cannot do GEP on non-lvalue"); iceAssert(type->getElementCount() > memberIndex && "struct does not have so many members"); Instruction* instr = make_instr(OpKind::Value_GetStructMember, false, type->getElementN(memberIndex), { structPtr, ConstantInt::getUNative(memberIndex) }, Value::Kind::lvalue); return instr; } Value* IRBuilder::StructGEP(Value* structPtr, size_t memberIndex, const std::string& vname) { if(!structPtr->islvalue()) error("irbuilder: cannot do GEP on non-lvalue"); if(structPtr->getType()->isStructType()) { auto st = structPtr->getType()->toStructType(); return this->addInstruction(doGEPOnCompoundType(st, structPtr, memberIndex), vname); } else if(structPtr->getType()->isTupleType()) { auto tt = structPtr->getType()->toTupleType(); return this->addInstruction(doGEPOnCompoundType(tt, structPtr, memberIndex), vname); } else if(structPtr->getType()->isClassType()) { error("irbuilder: classes do not support element access by index"); // auto ct = structPtr->getType()->toClassType(); // // to compensate for the vtable, we add one to the index if there is a vtable! // if(ct->getVirtualMethodCount() > 0) // memberIndex += 1; // return this->addInstruction(doGEPOnCompoundType(ct, // structPtr, memberIndex), vname); } else { error("irbuilder: type '%s' is not a valid type to GEP into", structPtr->getType()); } } Value* IRBuilder::GetStructMember(Value* ptr, const std::string& memberName) { if(!ptr->islvalue()) error("irbuilder: cannot do GEP on non-lvalue"); if(ptr->getType()->isStructType()) { auto st = ptr->getType()->toStructType(); auto memt = st->getElement(memberName); iceAssert(st->hasElementWithName(memberName) && "no element with such name"); Instruction* instr = make_instr(OpKind::Value_GetStructMember, false, memt, { ptr, ConstantInt::getUNative(st->getElementIndex(memberName)) }, Value::Kind::lvalue); return this->addInstruction(instr, memberName); } else if(ptr->getType()->isClassType()) { auto ct = ptr->getType()->toClassType(); iceAssert(ct->hasElementWithName(memberName) && "no element with such name"); auto memt = ct->getElement(memberName); //! VTABLE HANDLING size_t vTableOfs = 0; if(ct->getVirtualMethodCount() > 0) vTableOfs = 1; Instruction* instr = make_instr(OpKind::Value_GetStructMember, false, memt, { ptr, ConstantInt::getUNative(ct->getAbsoluteElementIndex(memberName) + vTableOfs) }, Value::Kind::lvalue); return this->addInstruction(instr, memberName); } else { error("irbuilder: type '%s' is not a valid type to GEP into", ptr->getType()); } } void IRBuilder::SetVtable(Value* ptr, Value* table) { if(!ptr->islvalue()) error("irbuilder: cannot do set vtable on non-lvalue"); auto ty = ptr->getType(); if(!ty->isClassType()) error("irbuilder: '%s' is not a class type", ty); if(table->getType() != Type::getInt8Ptr()) error("irbuilder: expected i8* for vtable, got '%s'", table->getType()); Instruction* instr = make_instr(OpKind::Value_GetStructMember, false, Type::getInt8Ptr(), { ptr, ConstantInt::getUNative(0) }, Value::Kind::lvalue); auto gep = this->addInstruction(instr, "__vtable"); this->Store(table, gep); } // equivalent to GEP(ptr*, ptrIndex, elmIndex) Value* IRBuilder::ConstGEP2(Value* ptr, size_t ptrIndex, size_t elmIndex, const std::string& vname) { if(!ptr->getType()->isPointerType()) error("irbuilder: ptr is not a pointer type (got '%s')", ptr->getType()); auto ptri = ConstantInt::getUNative(ptrIndex); auto elmi = ConstantInt::getUNative(elmIndex); return this->GEP2(ptr, ptri, elmi, vname); } // equivalent to GEP(ptr*, ptrIndex, elmIndex) Value* IRBuilder::GEP2(Value* ptr, Value* ptrIndex, Value* elmIndex, const std::string& vname) { if(!ptr->getType()->isPointerType()) error("irbuilder: ptr is not a pointer type (got '%s')", ptr->getType()); else if(ptr->getType()->getPointerElementType()->isClassType() || ptr->getType()->getPointerElementType()->isStructType()) error("irbuilder: use the other function for struct types"); iceAssert(ptrIndex->getType()->isIntegerType() && "ptrIndex is not integer type"); iceAssert(elmIndex->getType()->isIntegerType() && "elmIndex is not integer type"); Type* retType = ptr->getType()->getPointerElementType(); if(retType->isArrayType()) retType = retType->toArrayType()->getElementType()->getPointerTo(); if(ptr->getType()->isMutablePointer()) retType = retType->getMutablePointerVersion(); Instruction* instr = make_instr(OpKind::Value_GetGEP2, false, retType, { ptr, ptrIndex, elmIndex }); return this->addInstruction(instr, vname); } // equivalent to GEP(ptr*, index) Value* IRBuilder::GetPointer(Value* ptr, Value* ptrIndex, const std::string& vname) { if(!ptr->getType()->isPointerType()) error("irbuilder: ptr is not a pointer type (got '%s')", ptr->getType()); if(!ptrIndex->getType()->isIntegerType()) error("irbuilder: ptrIndex is not an integer type (got '%s')", ptrIndex->getType()); if(ptr->getType()->getPointerElementType()->isClassType() || ptr->getType()->getPointerElementType()->isStructType()) error("irbuilder: use the other function for struct types"); Instruction* instr = make_instr(OpKind::Value_GetPointer, false, ptr->getType(), { ptr, ptrIndex }); return this->addInstruction(instr, vname); } Value* IRBuilder::Select(Value* cond, Value* one, Value* two, const std::string& vname) { if(!cond->getType()->isBoolType()) error("irbuilder: cond is not a boolean type (got '%s')", cond->getType()); if(one->getType() != two->getType()) error("irbuilder: non-identical types for operands (got '%s' and '%s')", one->getType(), two->getType()); Instruction* instr = make_instr(OpKind::Value_Select, false, one->getType(), { cond, one, two }); return this->addInstruction(instr, vname); } Value* IRBuilder::Sizeof(Type* t, const std::string& vname) { Instruction* instr = make_instr(OpKind::Misc_Sizeof, false, Type::getNativeWord(), { ConstantValue::getZeroValue(t) }); return this->addInstruction(instr, vname); } Value* IRBuilder::CreateValue(Type* t, const std::string& vname) { auto ret = ConstantValue::getZeroValue(t); ret->setName(vname); return ret; } static Instruction* _insertValue(Value* val, size_t idx, Type* et, Value* elm) { Type* t = val->getType(); if(!t->isStructType() && !t->isClassType() && !t->isTupleType() && !t->isArrayType()) error("irbuilder: val is not an aggregate type (have '%s')", t); if(elm->getType() != et) { error("irbuilder: mismatched types for value and element -- trying to insert '%s' into '%s'", elm->getType(), et); } int ofs = 0; //! VTABLE HANDLING if(t->isClassType() && t->toClassType()->getVirtualMethodCount() > 0) ofs = 1; std::vector args = { val, elm, ConstantInt::getNative(idx + ofs) }; // note: no sideeffects, since we return a new aggregate return make_instr(OpKind::Value_InsertValue, false, t, args); } static Instruction* _extractValue(Value* val, size_t idx, Type* et) { Type* t = val->getType(); if(!t->isStructType() && !t->isClassType() && !t->isTupleType() && !t->isArrayType()) error("irbuilder: val is not an aggregate type (have '%s')", t); int ofs = 0; //! VTABLE HANDLING if(t->isClassType() && t->toClassType()->getVirtualMethodCount() > 0) ofs = 1; std::vector args = { val, ConstantInt::getNative(idx + ofs) }; // note: no sideeffects, since we return a new aggregate return make_instr(OpKind::Value_ExtractValue, false, et, args); } Value* IRBuilder::InsertValue(Value* val, const std::vector& inds, Value* elm, const std::string& vname) { Type* t = val->getType(); if(t->isClassType()) error("irbuilder: classes do not support element access by index"); if(!t->isStructType() && !t->isTupleType() && !t->isArrayType()) error("irbuilder: val is not a supported aggregate type (have '%s')", t); if(inds.size() != 1) error("irbuilder: must have exactly one index!"); Type* et = 0; if(t->isStructType()) et = t->toStructType()->getElementN(inds[0]); else if(t->isTupleType()) et = t->toTupleType()->getElementN(inds[0]); else if(t->isArrayType()) et = t->toArrayType()->getElementType(); iceAssert(et); return this->addInstruction(_insertValue(val, inds[0], et, elm), vname); } Value* IRBuilder::ExtractValue(Value* val, const std::vector& inds, const std::string& vname) { Type* t = val->getType(); if(!t->isStructType() && !t->isClassType() && !t->isTupleType() && !t->isArrayType()) error("irbuilder: val is not an aggregate type (have '%s')", t); if(inds.size() != 1) error("irbuilder: must have exactly one index!"); if(t->isClassType()) error("irbuilder: classes do not support element access by index"); Type* et = 0; if(t->isStructType()) et = t->toStructType()->getElementN(inds[0]); else if(t->isTupleType()) et = t->toTupleType()->getElementN(inds[0]); else if(t->isArrayType()) et = t->toArrayType()->getElementType(); iceAssert(et); return this->addInstruction(_extractValue(val, inds[0], et), vname); } Value* IRBuilder::InsertValueByName(Value* val, const std::string& n, Value* elm, const std::string& vname) { Type* t = val->getType(); if(!t->isStructType() && !t->isClassType()) error("irbuilder: val is not an aggregate type with named members (class or struct) (have '%s')", t); size_t ind = 0; Type* et = 0; if(t->isStructType()) ind = t->toStructType()->getElementIndex(n), et = t->toStructType()->getElement(n); else if(t->isClassType()) ind = t->toClassType()->getAbsoluteElementIndex(n), et = t->toClassType()->getElement(n); else iceAssert(0); return this->addInstruction(_insertValue(val, ind, et, elm), vname); } Value* IRBuilder::ExtractValueByName(Value* val, const std::string& n, const std::string& vname) { Type* t = val->getType(); if(!t->isStructType() && !t->isClassType()) error("irbuilder: val is not an aggregate type with named members (class or struct) (have '%s')", t); size_t ind = 0; Type* et = 0; if(t->isStructType()) ind = t->toStructType()->getElementIndex(n), et = t->toStructType()->getElement(n); else if(t->isClassType()) ind = t->toClassType()->getAbsoluteElementIndex(n), et = t->toClassType()->getElement(n); else iceAssert(0); return this->addInstruction(_extractValue(val, ind, et), vname); } Value* IRBuilder::GetSAAData(Value* arr, const std::string& vname) { if(!isSAAType(arr->getType())) error("irbuilder: thing is not an SAA type (got '%s')", arr->getType()); Instruction* instr = make_instr(OpKind::SAA_GetData, false, getSAAElmType(arr->getType())->getMutablePointerTo(), { arr }); return this->addInstruction(instr, vname); } Value* IRBuilder::SetSAAData(Value* arr, Value* val, const std::string& vname) { if(!isSAAType(arr->getType())) error("irbuilder: thing is not an SAA type (got '%s')", arr->getType()); auto t = getSAAElmType(arr->getType()); if(val->getType() != t->getMutablePointerTo()) { error("irbuilder: val is not a pointer to elm type (need '%s', have '%s')", t->getMutablePointerTo(), val->getType()); } Instruction* instr = make_instr(OpKind::SAA_SetData, true, arr->getType(), { arr, val }); return this->addInstruction(instr, vname); } Value* IRBuilder::GetSAALength(Value* arr, const std::string& vname) { if(!isSAAType(arr->getType())) error("irbuilder: thing is not an SAA type (got '%s')", arr->getType()); Instruction* instr = make_instr(OpKind::SAA_GetLength, false, Type::getNativeWord(), { arr }); return this->addInstruction(instr, vname); } Value* IRBuilder::SetSAALength(Value* arr, Value* val, const std::string& vname) { if(!isSAAType(arr->getType())) error("irbuilder: thing is not an SAA type (got '%s')", arr->getType()); if(val->getType() != Type::getNativeWord()) error("irbuilder: val is not an int64"); Instruction* instr = make_instr(OpKind::SAA_SetLength, true, arr->getType(), { arr, val }); return this->addInstruction(instr, vname); } Value* IRBuilder::GetSAACapacity(Value* arr, const std::string& vname) { if(!isSAAType(arr->getType())) error("irbuilder: thing is not an SAA type (got '%s')", arr->getType()); Instruction* instr = make_instr(OpKind::SAA_GetCapacity, false, Type::getNativeWord(), { arr }); return this->addInstruction(instr, vname); } Value* IRBuilder::SetSAACapacity(Value* arr, Value* val, const std::string& vname) { if(!isSAAType(arr->getType())) error("irbuilder: thing is not an SAA type (got '%s')", arr->getType()); if(val->getType() != Type::getNativeWord()) error("irbuilder: val is not an int64"); Instruction* instr = make_instr(OpKind::SAA_SetCapacity, true, arr->getType(), { arr, val }); return this->addInstruction(instr, vname); } Value* IRBuilder::GetSAARefCountPointer(Value* arr, const std::string& vname) { if(!isSAAType(arr->getType())) error("irbuilder: thing is not an SAA type (got '%s')", arr->getType()); Instruction* instr = make_instr(OpKind::SAA_GetRefCountPtr, false, Type::getNativeWordPtr(), { arr }); return this->addInstruction(instr, vname); } Value* IRBuilder::SetSAARefCountPointer(Value* arr, Value* val, const std::string& vname) { if(!isSAAType(arr->getType())) error("irbuilder: thing is not an SAA type (got '%s')", arr->getType()); if(val->getType() != Type::getNativeWord()->getPointerTo()) error("irbuilder: val is not an int64 pointer"); Instruction* instr = make_instr(OpKind::SAA_SetRefCountPtr, true, arr->getType(), { arr, val }); return this->addInstruction(instr, vname); } Value* IRBuilder::GetSAARefCount(Value* arr, const std::string& vname) { return this->ReadPtr(this->GetSAARefCountPointer(arr), vname); } void IRBuilder::SetSAARefCount(Value* arr, Value* val) { if(val->getType() != Type::getNativeWord()) error("irbuilder: val is not an int64"); this->WritePtr(val, this->PointerTypeCast(this->GetSAARefCountPointer(arr), Type::getNativeWordPtr()->getMutablePointerVersion())); } Value* IRBuilder::GetArraySliceData(Value* slc, const std::string& vname) { if(!slc->getType()->isArraySliceType()) error("irbuilder: slc is not an array slice type (got '%s')", slc->getType()); auto st = slc->getType()->toArraySliceType(); auto et = st->getElementType(); Instruction* instr = make_instr(OpKind::ArraySlice_GetData, false, st->isMutable() ? et->getMutablePointerTo() : et->getPointerTo(), { slc }); return this->addInstruction(instr, vname); } Value* IRBuilder::SetArraySliceData(Value* slc, Value* val, const std::string& vname) { if(!slc->getType()->isArraySliceType()) error("irbuilder: slc is not an array slice type (got '%s')", slc->getType()); auto st = slc->getType()->toArraySliceType(); auto et = st->getElementType(); auto pt = (st->isMutable() ? et->getMutablePointerTo() : et->getPointerTo()); if(val->getType() != pt) { if(pt->getPointerElementType() != val->getType()->getPointerElementType() || (pt->isMutablePointer() && val->getType()->isImmutablePointer())) error("irbuilder: val is not a pointer to elm type (need '%s', have '%s')", pt, val->getType()); } Instruction* instr = make_instr(OpKind::ArraySlice_SetData, true, slc->getType(), { slc, val }); return this->addInstruction(instr, vname); } Value* IRBuilder::GetArraySliceLength(Value* slc, const std::string& vname) { if(!slc->getType()->isArraySliceType()) error("irbuilder: slc is not an array slice type (got '%s')", slc->getType()); Instruction* instr = make_instr(OpKind::ArraySlice_GetLength, false, Type::getNativeWord(), { slc }); return this->addInstruction(instr, vname); } Value* IRBuilder::SetArraySliceLength(Value* slc, Value* val, const std::string& vname) { if(!slc->getType()->isArraySliceType()) error("irbuilder: slc is not an array slice type (got '%s')", slc->getType()); if(val->getType() != Type::getNativeWord()) error("irbuilder: val is not an int64"); Instruction* instr = make_instr(OpKind::ArraySlice_SetLength, true, slc->getType(), { slc, val }); return this->addInstruction(instr, vname); } Value* IRBuilder::GetAnyTypeID(Value* any, const std::string& vname) { if(!any->getType()->isAnyType()) error("irbuilder: not any type (got '%s')", any->getType()); Instruction* instr = make_instr(OpKind::Any_GetTypeID, false, Type::getNativeUWord(), { any }); return this->addInstruction(instr, vname); } Value* IRBuilder::SetAnyTypeID(Value* any, Value* val, const std::string& vname) { if(!any->getType()->isAnyType()) error("irbuilder: not any type (got '%s')", any->getType()); else if(val->getType() != Type::getNativeUWord()) error("irbuilder: val is not a uint64"); Instruction* instr = make_instr(OpKind::Any_SetTypeID, true, Type::getAny(), { any, val }); return this->addInstruction(instr, vname); } Value* IRBuilder::GetAnyData(Value* any, const std::string& vname) { if(!any->getType()->isAnyType()) error("irbuilder: not any type (got '%s')", any->getType()); Instruction* instr = make_instr(OpKind::Any_GetData, false, ArrayType::get(Type::getInt8(), BUILTIN_ANY_DATA_BYTECOUNT), { any }); return this->addInstruction(instr, vname); } Value* IRBuilder::SetAnyData(Value* any, Value* val, const std::string& vname) { if(!any->getType()->isAnyType()) error("irbuilder: not any type (got '%s')", any->getType()); else if(val->getType() != ArrayType::get(Type::getInt8(), BUILTIN_ANY_DATA_BYTECOUNT)) error("irbuilder: val is not array type (got '%s')", val->getType()); Instruction* instr = make_instr(OpKind::Any_SetData, true, Type::getAny(), { any, val }); return this->addInstruction(instr, vname); } Value* IRBuilder::GetAnyRefCountPointer(Value* arr, const std::string& vname) { if(!arr->getType()->isAnyType()) error("irbuilder: arr is not an any type (got '%s')", arr->getType()); Instruction* instr = make_instr(OpKind::Any_GetRefCountPtr, false, Type::getNativeWordPtr(), { arr }); return this->addInstruction(instr, vname); } Value* IRBuilder::SetAnyRefCountPointer(Value* arr, Value* val, const std::string& vname) { if(!arr->getType()->isAnyType()) error("irbuilder: arr is not an any type (got '%s')", arr->getType()); if(val->getType() != Type::getNativeWord()->getPointerTo()) error("irbuilder: val is not an int64 pointer"); Instruction* instr = make_instr(OpKind::Any_SetRefCountPtr, true, arr->getType(), { arr, val }); return this->addInstruction(instr, vname); } Value* IRBuilder::GetAnyRefCount(Value* arr, const std::string& vname) { return this->ReadPtr(this->GetAnyRefCountPointer(arr), vname); } void IRBuilder::SetAnyRefCount(Value* arr, Value* val) { if(val->getType() != Type::getNativeWord()) error("irbuilder: val is not an int64"); this->WritePtr(val, this->PointerTypeCast(this->GetAnyRefCountPointer(arr), Type::getNativeWordPtr()->getMutablePointerVersion())); } Value* IRBuilder::GetRangeLower(Value* range, const std::string& vname) { if(!range->getType()->isRangeType()) error("irbuilder: range is not a range type (have '%s')", range->getType()); Instruction* instr = make_instr(OpKind::Range_GetLower, false, Type::getNativeWord(), { range }); return this->addInstruction(instr, vname); } Value* IRBuilder::SetRangeLower(Value* range, Value* val, const std::string& vname) { if(!range->getType()->isRangeType()) error("irbuilder: range is not a range type (got '%s')", range->getType()); if(!val->getType()->isIntegerType()) error("irbuilder: val is not an integer type (got '%s')", val->getType()); Instruction* instr = make_instr(OpKind::Range_SetLower, true, Type::getRange(), { range, val }); return this->addInstruction(instr, vname); } Value* IRBuilder::GetRangeUpper(Value* range, const std::string& vname) { if(!range->getType()->isRangeType()) error("irbuilder: range is not a range type (have '%s')", range->getType()); Instruction* instr = make_instr(OpKind::Range_GetUpper, false, Type::getNativeWord(), { range }); return this->addInstruction(instr, vname); } Value* IRBuilder::SetRangeUpper(Value* range, Value* val, const std::string& vname) { if(!range->getType()->isRangeType()) error("irbuilder: range is not a range type (got '%s')", range->getType()); if(!val->getType()->isIntegerType()) error("irbuilder: val is not an integer type (got '%s')", val->getType()); Instruction* instr = make_instr(OpKind::Range_SetUpper, true, Type::getRange(), { range, val }); return this->addInstruction(instr, vname); } Value* IRBuilder::GetRangeStep(Value* range, const std::string& vname) { if(!range->getType()->isRangeType()) error("irbuilder: range is not a range type (have '%s')", range->getType()); Instruction* instr = make_instr(OpKind::Range_GetStep, false, Type::getNativeWord(), { range }); return this->addInstruction(instr, vname); } Value* IRBuilder::SetRangeStep(Value* range, Value* val, const std::string& vname) { if(!range->getType()->isRangeType()) error("irbuilder: range is not a range type (got '%s')", range->getType()); if(!val->getType()->isIntegerType()) error("irbuilder: val is not an integer type (got '%s')", val->getType()); Instruction* instr = make_instr(OpKind::Range_SetStep, true, Type::getRange(), { range, val }); return this->addInstruction(instr, vname); } Value* IRBuilder::GetEnumCaseIndex(Value* ecs, const std::string& vname) { if(!ecs->getType()->isEnumType()) error("irbuilder: enum is not an enum type (got '%s')", ecs->getType()); Instruction* instr = make_instr(OpKind::Enum_GetIndex, true, Type::getNativeWord(), { ecs }); return this->addInstruction(instr, vname); } Value* IRBuilder::SetEnumCaseIndex(Value* ecs, Value* idx, const std::string& vname) { if(!ecs->getType()->isEnumType()) error("irbuilder: enum is not an enum type (got '%s')", ecs->getType()); if(!idx->getType()->isIntegerType()) error("irbuilder: index is not an integer type (got '%s')", idx->getType()); Instruction* instr = make_instr(OpKind::Enum_SetIndex, true, ecs->getType(), { ecs, idx }); return this->addInstruction(instr, vname); } Value* IRBuilder::GetEnumCaseValue(Value* ecs, const std::string& vname) { if(!ecs->getType()->isEnumType()) error("irbuilder: enum is not an enum type (got '%s')", ecs->getType()); Instruction* instr = make_instr(OpKind::Enum_GetValue, true, ecs->getType()->toEnumType()->getCaseType(), { ecs }); return this->addInstruction(instr, vname); } Value* IRBuilder::SetEnumCaseValue(Value* ecs, Value* val, const std::string& vname) { if(!ecs->getType()->isEnumType()) error("irbuilder: enum is not an enum type (got '%s')", ecs->getType()); if(ecs->getType()->toEnumType()->getCaseType() != val->getType()) { error("irbuilder: value type mismatch (enum case type is '%s', value type is '%s'", ecs->getType()->toEnumType()->getCaseType(), val->getType()); } Instruction* instr = make_instr(OpKind::Enum_SetValue, true, ecs->getType(), { ecs, val }); return this->addInstruction(instr, vname); } Value* IRBuilder::ReadPtr(Value* ptr, const std::string& vname) { if(!ptr->getType()->isPointerType()) error("irbuilder: ptr is not pointer type (got '%s')", ptr->getType()); Instruction* instr = make_instr(OpKind::Value_ReadPtr, false, ptr->getType()->getPointerElementType(), { ptr }); return this->addInstruction(instr, vname); } void IRBuilder::WritePtr(Value* v, Value* ptr) { if(!ptr->getType()->isPointerType()) error("irbuilder: ptr is not pointer type (got '%s')", ptr->getType()); if(ptr->getType()->isImmutablePointer()) error("irbuilder: cannot store value to immutable pointer type '%s'", ptr->getType()); auto vt = v->getType(); auto pt = ptr->getType(); if(vt != pt->getPointerElementType()) { //* here, we know that the storage pointer is mutable. there's a special edge-case we need to catch: //* if we're storing a value of type &T to a & &mut T, or a &mut T to a & &T. //* in those cases, the mutability of the base type doesn't matter at all. At the LLVM level, we don't even make a distinction, //* so we can safely pass this onto the translation layer without worrying about it. // if((vt->isPointerType() && pt->isPointerType() && vt->getPointerElementType() == pt->getPointerElementType()) == false) error("irbuilder: ptr is not a pointer to type of value (base types '%s' -> '%s' differ)", vt, pt->getPointerElementType()); } Instruction* instr = make_instr(OpKind::Value_WritePtr, true, Type::getVoid(), { v, ptr }); this->addInstruction(instr, ""); } static std::pair getInstrThatMakesLValue(IRBuilder* irb, Type* type, const std::string& vname) { Instruction* instr = make_instr(OpKind::Value_CreateLVal, true, type, { ConstantValue::getZeroValue(type) }, Value::Kind::lvalue); Value* ret = instr->realOutput; ret->setName(vname); // get the parent function auto parent = irb->getCurrentBlock()->getParentFunction(); iceAssert(parent); parent->addStackAllocation(type); // get the entry block auto entry = parent->getBlockList().front(); iceAssert(entry); return { instr, entry }; } Value* IRBuilder::CreateLValue(Type* type, const std::string& vname) { auto [ instr, entry ] = getInstrThatMakesLValue(this, type, vname); // needs to be hoisted also entry->instructions.insert(entry->instructions.begin(), instr); return instr->realOutput; } void IRBuilder::Store(Value* val, Value* lval) { if(lval->isConst()) error("irbuilder: cannot store to constant lvalue"); else if(!lval->islvalue()) error("irbuilder: cannot store to non-lvalue"); else if(val->getType() != lval->getType()) error("irbuilder: cannot store value of type '%s' to lvalue of type '%s'", val->getType(), lval->getType()); // ok... Instruction* instr = make_instr(OpKind::Value_Store, true, Type::getVoid(), { val, lval }); this->addInstruction(instr, ""); } Value* IRBuilder::Dereference(Value* val, const std::string& vname) { if(!val->getType()->isPointerType()) error("irbuilder: cannot dereference non-pointer type '%s'", val->getType()); Instruction* instr = make_instr(OpKind::Value_Dereference, true, val->getType()->getPointerElementType(), { val }, Value::Kind::lvalue); if(val->getType()->isImmutablePointer()) instr->realOutput->makeConst(); return this->addInstruction(instr, vname); } Value* IRBuilder::AddressOf(Value* lval, bool mut, const std::string& vname) { if(!lval->islvalue()) error("irbuilder: cannot take the address of a non-lvalue"); // ok... Instruction* instr = make_instr(OpKind::Value_AddressOf, true, mut ? lval->getType()->getMutablePointerTo() : lval->getType()->getPointerTo(), { lval }); return this->addInstruction(instr, vname); } Value* IRBuilder::SetUnionVariantData(Value* unn, size_t id, Value* data, const std::string& vname) { if(!unn->getType()->isUnionType()) error("irbuilder: '%s' is not a union type", unn->getType()); auto ut = unn->getType()->toUnionType(); if(data->getType() != ut->getVariant(id)->getInteriorType()) error("irbuilder: cannot store data '%s' into union variant '%s'", data->getType(), ut->getVariant(id)->getInteriorType()); Instruction* instr = make_instr(OpKind::Union_SetValue, true, unn->getType(), { unn, ConstantInt::getNative(id), data }); return this->addInstruction(instr, vname); } Value* IRBuilder::GetUnionVariantData(Value* unn, size_t id, const std::string& vname) { if(!unn->getType()->isUnionType()) error("irbuilder: '%s' is not a union type", unn->getType()); auto ut = unn->getType()->toUnionType(); Instruction* instr = make_instr(OpKind::Union_GetValue, true, ut->getVariant(id)->getInteriorType(), { unn, ConstantInt::getNative(id) }); return this->addInstruction(instr, vname); } Value* IRBuilder::GetUnionVariantID(Value* unn, const std::string& vname) { if(!unn->getType()->isUnionType()) error("irbuilder: '%s' is not a union type", unn->getType()); Instruction* instr = make_instr(OpKind::Union_GetVariantID, true, Type::getNativeWord(), { unn }); return this->addInstruction(instr, vname); } Value* IRBuilder::SetUnionVariantID(Value* unn, size_t id, const std::string& vname) { if(!unn->getType()->isUnionType()) error("irbuilder: '%s' is not a union type", unn->getType()); Instruction* instr = make_instr(OpKind::Union_SetVariantID, true, unn->getType(), { unn, ConstantInt::getNative(id) }); return this->addInstruction(instr, vname); } void IRBuilder::Unreachable() { this->addInstruction(make_instr(OpKind::Unreachable, true, Type::getVoid(), { }), ""); } IRBlock* IRBuilder::addNewBlockInFunction(const std::string& name, Function* func) { IRBlock* block = new IRBlock(func); if(func != this->currentFunction) { // warn("changing current function in irbuilder (from %s to %s)", // (this->currentFunction ? this->currentFunction->getName().str() : "null"), // func->getName() // ); this->currentFunction = block->parentFunction; } this->currentFunction->blocks.push_back(block); size_t cnt = 0; for(auto b : this->currentFunction->blocks) if(b->getName().str() == name) cnt++; block->setName(strprintf("%s%s", name, cnt > 0 ? strprintf(".%d", cnt) : "")); return block; } IRBlock* IRBuilder::addNewBlockAfter(const std::string& name, IRBlock* block) { IRBlock* nb = new IRBlock(block->parentFunction); if(nb->parentFunction != this->currentFunction) { // warn("changing current function in irbuilder (from %s to %s)", // (this->currentFunction ? this->currentFunction->getName().str() : "null"), // nb->parentFunction->getName() // ); this->currentFunction = nb->parentFunction; } for(size_t i = 0; i < this->currentFunction->blocks.size(); i++) { IRBlock* b = this->currentFunction->blocks[i]; if(b == block) { size_t cnt = 0; for(auto bk : this->currentFunction->blocks) if(bk->getName().str() == name) cnt++; nb->setName(strprintf("%s%s", name, cnt > 0 ? strprintf(".%d", cnt) : "")); this->currentFunction->blocks.insert(this->currentFunction->blocks.begin() + i + 1, nb); return nb; } } iceAssert(0 && "no such block to insert after"); nb->setName(name); return nb; } } ================================================ FILE: source/fir/Instruction.cpp ================================================ // Instruction.cpp // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #include "ir/block.h" #include "ir/function.h" #include "ir/constant.h" #include "ir/instruction.h" #include "memorypool.h" namespace fir { static util::MemoryPool value_pool; Instruction::Instruction(OpKind kind, bool sideeff, Type* out, const std::vector& vals) : Instruction(kind, sideeff, out, vals, Value::Kind::prvalue) { } Instruction::Instruction(OpKind kind, bool sideeff, Type* out, const std::vector& vals, Value::Kind k) : Value(out) { this->opKind = kind; this->operands = vals; this->sideEffects = sideeff; this->realOutput = value_pool.construct(out, k); } Value* Instruction::getResult() { if(this->realOutput) return this->realOutput; error("calling getActualValue() when not in function! (no real value)"); } bool Instruction::hasSideEffects() { return this->sideEffects; } void Instruction::setValue(Value* v) { this->realOutput = v; } void Instruction::clearValue() { this->realOutput = 0; } std::string Instruction::str() { std::string instrname; switch(this->opKind) { case OpKind::Signed_Add: instrname = "sadd"; break; case OpKind::Signed_Sub: instrname = "ssub"; break; case OpKind::Signed_Mul: instrname = "smul"; break; case OpKind::Signed_Div: instrname = "sdiv"; break; case OpKind::Signed_Mod: instrname = "srem"; break; case OpKind::Signed_Neg: instrname = "neg"; break; case OpKind::Unsigned_Add: instrname = "uadd"; break; case OpKind::Unsigned_Sub: instrname = "usub"; break; case OpKind::Unsigned_Mul: instrname = "umul"; break; case OpKind::Unsigned_Div: instrname = "udiv"; break; case OpKind::Unsigned_Mod: instrname = "urem"; break; case OpKind::Floating_Add: instrname = "fadd"; break; case OpKind::Floating_Sub: instrname = "fsub"; break; case OpKind::Floating_Mul: instrname = "fmul"; break; case OpKind::Floating_Div: instrname = "fdiv"; break; case OpKind::Floating_Mod: instrname = "frem"; break; case OpKind::Floating_Neg: instrname = "fneg"; break; case OpKind::Floating_Truncate: instrname = "ftrunc"; break; case OpKind::Floating_Extend: instrname = "fext"; break; case OpKind::ICompare_Equal: instrname = "icmp eq"; break; case OpKind::ICompare_NotEqual: instrname = "icmp ne"; break; case OpKind::ICompare_Greater: instrname = "icmp gt"; break; case OpKind::ICompare_Less: instrname = "icmp lt"; break; case OpKind::ICompare_GreaterEqual: instrname = "icmp ge"; break; case OpKind::ICompare_LessEqual: instrname = "icmp le"; break; case OpKind::FCompare_Equal_ORD: instrname = "fcmp ord eq"; break; case OpKind::FCompare_Equal_UNORD: instrname = "fcmp unord eq"; break; case OpKind::FCompare_NotEqual_ORD: instrname = "fcmp ord ne"; break; case OpKind::FCompare_NotEqual_UNORD: instrname = "fcmp unord ne"; break; case OpKind::FCompare_Greater_ORD: instrname = "fcmp ord gt"; break; case OpKind::FCompare_Greater_UNORD: instrname = "fcmp unord gt"; break; case OpKind::FCompare_Less_ORD: instrname = "fcmp ord lt"; break; case OpKind::FCompare_Less_UNORD: instrname = "fcmp unord lt"; break; case OpKind::FCompare_GreaterEqual_ORD: instrname = "fcmp ord ge"; break; case OpKind::FCompare_GreaterEqual_UNORD: instrname = "fcmp unord ge"; break; case OpKind::FCompare_LessEqual_ORD: instrname = "fcmp ord le"; break; case OpKind::FCompare_LessEqual_UNORD: instrname = "fcmp unord le"; break; case OpKind::ICompare_Multi: instrname = "icmp multi"; break; case OpKind::FCompare_Multi: instrname = "fcmp multi"; break; case OpKind::Bitwise_Not: instrname = "not"; break; case OpKind::Bitwise_Xor: instrname = "xor"; break; case OpKind::Bitwise_Arithmetic_Shr: instrname = "ashr"; break; case OpKind::Bitwise_Logical_Shr: instrname = "lshr"; break; case OpKind::Bitwise_Shl: instrname = "shl"; break; case OpKind::Bitwise_And: instrname = "and"; break; case OpKind::Bitwise_Or: instrname = "or"; break; case OpKind::Cast_Bitcast: instrname = "bitcast"; break; case OpKind::Cast_IntSize: instrname = "intszcast"; break; case OpKind::Cast_Signedness: instrname = "signedcast"; break; case OpKind::Cast_FloatToInt: instrname = "fptoint"; break; case OpKind::Cast_IntToFloat: instrname = "inttofp"; break; case OpKind::Cast_PointerType: instrname = "ptrcast"; break; case OpKind::Cast_PointerToInt: instrname = "ptrtoint"; break; case OpKind::Cast_IntToPointer: instrname = "inttoptr"; break; case OpKind::Cast_IntSignedness: instrname = "signcast"; break; case OpKind::Integer_ZeroExt: instrname = "izeroext"; break; case OpKind::Integer_Truncate: instrname = "itrunc"; break; case OpKind::Value_WritePtr: instrname = "writemem"; break; case OpKind::Logical_Not: instrname = "logicalNot"; break; case OpKind::Value_ReadPtr: instrname = "readmem"; break; case OpKind::Value_StackAlloc: instrname = "stackAlloc"; break; case OpKind::Value_CallFunction: instrname = "call"; break; case OpKind::Value_CallFunctionPointer: instrname = "callfp"; break; case OpKind::Value_CallVirtualMethod: instrname = "callvirtual"; break; case OpKind::Value_Return: instrname = "ret"; break; case OpKind::Value_GetPointerToStructMember: instrname = "gep"; break; case OpKind::Value_GetStructMember: instrname = "gep"; break; case OpKind::Value_GetPointer: instrname = "gep"; break; case OpKind::Value_GetGEP2: instrname = "gep"; break; case OpKind::Value_InsertValue: instrname = "insertval"; break; case OpKind::Value_ExtractValue: instrname = "extractval"; break; case OpKind::Value_Select: instrname = "select"; break; case OpKind::Misc_Sizeof: instrname = "sizeof"; break; case OpKind::Branch_UnCond: instrname = "jump"; break; case OpKind::Branch_Cond: instrname = "branch"; break; case OpKind::Value_CreatePHI: instrname = "phi"; break; case OpKind::SAA_GetData: instrname = "get_saa.data"; break; case OpKind::SAA_SetData: instrname = "set_saa.data"; break; case OpKind::SAA_GetLength: instrname = "get_saa.len"; break; case OpKind::SAA_SetLength: instrname = "set_saa.len"; break; case OpKind::SAA_GetCapacity: instrname = "get_saa.cap"; break; case OpKind::SAA_SetCapacity: instrname = "set_saa.cap"; break; case OpKind::SAA_GetRefCountPtr: instrname = "get_saa.rc_ptr"; break; case OpKind::SAA_SetRefCountPtr: instrname = "set_saa.rc_ptr"; break; case OpKind::ArraySlice_GetData: instrname = "get_slice.data"; break; case OpKind::ArraySlice_SetData: instrname = "set_slice.data"; break; case OpKind::ArraySlice_GetLength: instrname = "get_slice.len"; break; case OpKind::ArraySlice_SetLength: instrname = "set_slice.len"; break; case OpKind::Any_GetData: instrname = "get_any.data"; break; case OpKind::Any_SetData: instrname = "set_any.data"; break; case OpKind::Any_GetTypeID: instrname = "get_any.typeid"; break; case OpKind::Any_SetTypeID: instrname = "set_any.typeid"; break; case OpKind::Any_GetRefCountPtr: instrname = "get_any.rc_ptr"; break; case OpKind::Any_SetRefCountPtr: instrname = "set_any.rc_ptr"; break; case OpKind::Range_GetLower: instrname = "get_range.lower"; break; case OpKind::Range_SetLower: instrname = "set_range.lower"; break; case OpKind::Range_GetUpper: instrname = "get_range.upper"; break; case OpKind::Range_SetUpper: instrname = "set_range.upper"; break; case OpKind::Range_GetStep: instrname = "get_range.step"; break; case OpKind::Range_SetStep: instrname = "set_range.step"; break; case OpKind::Enum_GetIndex: instrname = "get_enum.index"; break; case OpKind::Enum_SetIndex: instrname = "set_enum.index"; break; case OpKind::Enum_GetValue: instrname = "get_enum.value"; break; case OpKind::Enum_SetValue: instrname = "set_enum.value"; break; case OpKind::Union_SetValue: instrname = "set_union.value"; break; case OpKind::Union_GetValue: instrname = "get_union.value"; break; case OpKind::Union_GetVariantID: instrname = "get_union.id"; break; case OpKind::Union_SetVariantID: instrname = "set_union.id"; break; case OpKind::RawUnion_GEP: instrname = "raw_union_gep"; break; case OpKind::Value_AddressOf: instrname = "addrof"; break; case OpKind::Value_Store: instrname = "store"; break; case OpKind::Value_Dereference: instrname = "dereference"; break; case OpKind::Value_CreateLVal: instrname = "make_lval"; break; case OpKind::Unreachable: instrname = ""; break; case OpKind::Invalid: instrname = ""; break; } std::string ops; bool endswithfn = false; if(this->opKind == OpKind::Value_CreatePHI) { auto phi = dcast(PHINode, this->realOutput); iceAssert(phi); std::string nodes; for(auto i : phi->getValues()) nodes += strprintf("[$%s -> %%%d], ", i.first->getName().name, i.second->id); ops += nodes; } else { for(auto op : this->operands) { bool didfn = false; if(op->getType()->isFunctionType()) { ops += "@" + op->getName().str(); if(this->opKind == OpKind::Value_CallFunction) { ops += ", ("; didfn = true; } } else if(ConstantInt* ci = dcast(ConstantInt, op)) { ops += std::to_string(ci->getSignedValue()); } else if(ConstantFP* cf = dcast(ConstantFP, op)) { ops += std::to_string(cf->getValue()); } else if(ConstantBool* cb = dcast(ConstantBool, op)) { ops += cb->getValue() ? "true" : "false"; } else if(ConstantArraySlice* cas = dcast(ConstantArraySlice, op)) { ops += "(const slice %" + std::to_string(op->id) + ": ptr: %" + std::to_string(cas->getData()->id) + ", len: %" + std::to_string(cas->getLength()->id) + ") :: " + op->getType()->str(); } else if(dcast(ConstantValue, op)) { ops += "(const %" + std::to_string(op->id) + " :: " + op->getType()->str() + ")"; } else if(IRBlock* ib = dcast(IRBlock, op)) { ops += strprintf("$%d/%s", ib->id, ib->getName().str()); } else { auto name = op->getName().str(); if(name.empty()) name += " "; ops += strprintf("%s(%s%%%d) :: %s", name, op->islvalue() ? "*" : "", op->id, op->getType()); } if(!didfn) ops += ", "; endswithfn = didfn; } } if(ops.length() > 0 && !endswithfn) ops = ops.substr(0, ops.length() - 2); if(this->opKind == OpKind::Value_CallFunction) ops += ")"; std::string ret = ""; if(this->realOutput->getType()->isVoidType()) { ret = instrname + " " + ops; } else { auto name = this->realOutput->getName().str(); ret = name + (name.empty() ? "" : " ") + "(%" + std::to_string(this->realOutput->id) + ") :: " + this->realOutput->getType()->str() + " = " + instrname + " " + ops; } // return strprintf("!%d ", this->id) + ret; return ret; } } ================================================ FILE: source/fir/Module.cpp ================================================ // Module.cpp // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #include "string_consts.h" #include "ir/module.h" #include "ir/irbuilder.h" namespace fir { Module::Module(const std::string& nm) { this->moduleName = nm; } void Module::finaliseGlobalConstructors() { auto builder = IRBuilder(this); auto entryfunc = this->entryFunction; if(!entryfunc) { // keep trying various things. std::vector trymains = { "main", "_FF" + this->getModuleName() + "4main_FAv" }; for(const auto& m : trymains) { entryfunc = this->getFunction(Name::of(m)); if(entryfunc) break; } if(entryfunc) this->entryFunction = entryfunc; else error("fir: no entry point marked with '@entry', and no 'main' function; cannot compile program"); } // it doesn't actually matter what the entry function is named -- we just need to insert some instructions at the beginning. iceAssert(entryfunc); { iceAssert(entryfunc->getBlockList().size() > 0); auto oldentry = entryfunc->getBlockList()[0]; auto newentry = new IRBlock(entryfunc); newentry->setName("entryblock_entry"); auto& blklist = entryfunc->getBlockList(); blklist.insert(blklist.begin(), newentry); builder.setCurrentBlock(newentry); auto gif = this->getFunction(Name::obfuscate(strs::names::GLOBAL_INIT_FUNCTION)); if(!gif) error("fir: failed to find global init function"); builder.Call(gif); builder.UnCondBranch(oldentry); } } GlobalVariable* Module::createGlobalVariable(const Name& ident, Type* type, ConstantValue* initVal, bool isImmut, LinkageType linkage) { GlobalVariable* gv = new GlobalVariable(ident, this, type, isImmut, linkage, initVal); if(this->globals.find(ident) != this->globals.end()) error("fir: already have a global with name '%s'", ident.str()); this->globals[ident] = gv; return gv; } GlobalVariable* Module::createGlobalVariable(const Name& id, Type* type, bool isImmut, LinkageType linkage) { return this->createGlobalVariable(id, type, 0, isImmut, linkage); } GlobalVariable* Module::declareGlobalVariable(const Name& id, Type* type, bool isImmut) { return this->createGlobalVariable(id, type, 0, isImmut, LinkageType::External); } GlobalVariable* Module::tryGetGlobalVariable(const Name& id) { if(this->globals.find(id) == this->globals.end()) return 0; return this->globals[id]; } GlobalVariable* Module::getGlobalVariable(const Name& id) { if(this->globals.find(id) == this->globals.end()) error("fir: no such global with name '%s'", id.str()); return this->globals[id]; } GlobalVariable* Module::getOrCreateVirtualTableForClass(ClassType* cls) { if(this->vtables.find(cls) == this->vtables.end()) { auto fmethods = std::vector(cls->virtualMethodCount); auto methods = std::vector(cls->virtualMethodCount); for(auto meth : cls->reverseVirtualMethodMap) { methods[meth.first] = ConstantBitcast::get(meth.second, FunctionType::get({ }, Type::getVoid())); fmethods[meth.first] = meth.second; } //! ACHTUNG ! // TODO: should we make the vtable immutable? auto table = ConstantArray::get(ArrayType::get(FunctionType::get({ }, Type::getVoid()), cls->virtualMethodCount), methods); auto vtab = this->createGlobalVariable(Name::obfuscate("vtable", cls->getTypeName().mangled()), table->getType(), table, true, LinkageType::External); this->vtables[cls] = { fmethods, vtab }; } return this->vtables[cls].second; } Function* Module::getEntryFunction() { return this->entryFunction; } void Module::setEntryFunction(Function* fn) { this->entryFunction = fn; } Type* Module::getNamedType(const Name& id) { if(this->namedTypes.find(id) == this->namedTypes.end()) error("fir: no such type with name '%s'", id.str()); return this->namedTypes[id]; } void Module::addNamedType(const Name& id, Type* type) { if(this->namedTypes.find(id) != this->namedTypes.end()) error("fir: type '%s' exists already", id.str()); this->namedTypes[id] = type; } void Module::addFunction(Function* func) { if(this->functions.find(func->getName()) != this->functions.end()) error("fir: function '%s' exists already", func->getName().str()); this->functions[func->getName()] = func; } void Module::removeFunction(Function* func) { if(this->functions.find(func->getName()) == this->functions.end()) error("fir: function '%s' does not exist, cannot remove", func->getName().str()); this->functions.erase(func->getName()); } Function* Module::declareFunction(const Name& id, FunctionType* ftype) { return this->getOrCreateFunction(id, ftype, fir::LinkageType::External); } Function* Module::getFunction(const Name& id) { if(this->functions.find(id) == this->functions.end()) return 0; return this->functions[id]; } std::vector Module::getFunctionsWithName(const Name& id) { // todo: *very* inefficient. std::vector ret; for(const auto& [ ident, fn ] : this->functions) { if(ident == id) ret.push_back(fn); } return ret; } Function* Module::getOrCreateFunction(const Name& id, FunctionType* ftype, LinkageType linkage) { if(this->functions.find(id) != this->functions.end()) { if(!this->functions[id]->getType()->isTypeEqual(ftype)) { error("fir: function '%s' redeclared with different type (have '%s', new '%s')", id.str(), this->functions[id]->getType(), ftype); } return this->functions[id]; } Function* f = new Function(id, ftype, this, linkage); this->functions[id] = f; return f; } GlobalVariable* Module::createGlobalString(const std::string& str) { static int stringId = 0; if(this->globalStrings.find(str) != this->globalStrings.end()) return this->globalStrings[str]; GlobalVariable* gs = new GlobalVariable(Name::obfuscate("static_string", std::to_string(stringId++)), this, Type::getInt8Ptr(), true, LinkageType::Internal, 0); gs->setKind(Value::Kind::prvalue); return (this->globalStrings[str] = gs); } std::string Module::print() { std::string ret; ret = "# MODULE = " + this->getModuleName() + "\n"; for(const auto& [ str, gv ] : this->globalStrings) { ret += "global string (%" + std::to_string(gv->id); std::string copy; for(auto c : str) { if(c == '\r') copy += "\\r"; else if(c == '\n') copy += "\\n"; else if(c == '\t') copy += "\\t"; else copy += c; } ret += ") [" + std::to_string(str.length()) + "] = \"" + copy + "\"\n"; } for(auto global : this->globals) { ret += "global " + global.first.str() + " (%" + std::to_string(global.second->id) + ") :: " + global.second->getType()->str() + "\n"; } for(auto type : this->namedTypes) { // should just automatically create it. std::string tl; if(type.second->isStructType()) tl = fir::Type::typeListToString(type.second->toStructType()->getElements()); else if(type.second->isClassType()) tl = fir::Type::typeListToString(type.second->toClassType()->getElements()); else if(type.second->isTupleType()) tl = fir::Type::typeListToString(type.second->toTupleType()->getElements()); ret += "declare type :: " + type.second->str() + " { " + tl + " }\n"; } for(const auto& [ id, fp ] : this->functions) { Function* ffn = fp; std::string decl; // note: .str() already gives us the parameters decl += (ffn->isAlwaysInlined() ? "inline func: " : "func: ") + ffn->getName().str(); if(ffn->blocks.size() == 0) { decl += " -> "; decl += ffn->getReturnType()->str(); decl += "\n"; ret += "declare " + decl; continue; } ret += decl; ret += " -> "; ret += ffn->getReturnType()->str(); ret += " # mangled = " + ffn->getName().mangled(); ret += "\n{"; // do the args for(auto arg : ffn->getArguments()) { ret += strprintf("\n arg %s (%%%d) :: %s", arg->getName().name, arg->id, arg->getType()->str()); } for(auto block : ffn->getBlockList()) { ret += "\n (%" + std::to_string(block->id) + ") " + block->getName().str() + ":\n"; for(auto inst : block->instructions) ret += " " + inst->str() + "\n"; } ret += ("}\n\n"); } return ret; } Function* Module::getIntrinsicFunction(const std::string& id) { auto name = Name::of(""); FunctionType* ft = 0; if(id == "memcpy") { name = Name::of("memcpy"); ft = FunctionType::get({ fir::Type::getMutInt8Ptr(), fir::Type::getInt8Ptr(), fir::Type::getNativeWord(), fir::Type::getBool() }, fir::Type::getVoid()); } else if(id == "memmove") { name = Name::of("memmove"); ft = FunctionType::get({ fir::Type::getMutInt8Ptr(), fir::Type::getMutInt8Ptr(), fir::Type::getNativeWord(), fir::Type::getBool() }, fir::Type::getVoid()); } else if(id == "memset") { name = Name::of("memset"); ft = FunctionType::get({ fir::Type::getMutInt8Ptr(), fir::Type::getInt8(), fir::Type::getNativeWord(), fir::Type::getBool() }, fir::Type::getVoid()); } else if(id == "memcmp") { // note: memcmp isn't an actual llvm intrinsic, but we support it anyway // at llvm-translate-time, we make a function. name = Name::of("memcmp"); ft = FunctionType::get({ fir::Type::getInt8Ptr(), fir::Type::getInt8Ptr(), fir::Type::getNativeWord(), fir::Type::getBool() }, fir::Type::getInt32()); } else if(id == "roundup_pow2") { // rounds up to the nearest power of 2 // 127 -> 128 // 1 -> 1 // 40 -> 64 name = Name::of("roundup_pow2"); ft = FunctionType::get({ fir::Type::getNativeWord() }, fir::Type::getNativeWord()); } if(this->intrinsicFunctions.find(name) != this->intrinsicFunctions.end()) return this->intrinsicFunctions[name]; this->intrinsicFunctions[name] = new Function(name, ft, this, LinkageType::Internal); return this->intrinsicFunctions[name]; } std::vector Module::getGlobalVariables() { std::vector ret; ret.reserve(this->globals.size()); for(const auto& g : this->globals) ret.push_back(g.second); return ret; } std::vector Module::getNamedTypes() { std::vector ret; ret.reserve(this->namedTypes.size()); for(const auto& g : this->namedTypes) ret.push_back(g.second); return ret; } std::vector Module::getAllFunctions() { std::vector ret; ret.reserve(this->functions.size()); for(const auto& g : this->functions) ret.push_back(g.second); return ret; } std::string Module::getModuleName() { return this->moduleName; } void Module::setModuleName(const std::string& name) { this->moduleName = name; } } ================================================ FILE: source/fir/Name.cpp ================================================ // Name.cpp // Copyright (c) 2020, zhiayang // Licensed under the Apache License Version 2.0. #include "ir/type.h" namespace fir { bool Name::operator== (const Name& other) const { return this->name == other.name && this->scope == other.scope && this->params == other.params && this->retty == other.retty && this->kind == other.kind; } bool Name::operator!= (const Name& other) const { return !(*this == other); } Name Name::of(std::string name) { return Name(NameKind::Name, name, { }, { }, nullptr); } Name Name::of(std::string name, std::vector scope) { return Name(NameKind::Name, name, scope, { }, nullptr); } Name Name::type(std::string name) { return Name(NameKind::Type, name, { }, { }, nullptr); } Name Name::type(std::string name, std::vector scope) { return Name(NameKind::Type, name, scope, { }, nullptr); } Name Name::function(std::string name, std::vector params, fir::Type* retty) { return Name(NameKind::Function, name, { }, params, retty); } Name Name::function(std::string name, std::vector scope, std::vector params, fir::Type* retty) { return Name(NameKind::Function, name, scope, params, retty); } static std::string mangleScopeOnly(const fir::Name& id) { bool first = true; std::string ret; for(const auto& s : id.scope) { ret += (!first ? std::to_string(s.length()) : "") + s; first = false; } return ret; } static inline std::string lentypestr(const std::string& s) { return std::to_string(s.length()) + s; } static std::string mangleScopeName(const fir::Name& id) { return mangleScopeOnly(id) + lentypestr(id.name); } static std::string mangleType(fir::Type* t) { if(t->isPrimitiveType()) { return lentypestr(t->encodedStr()); } if(t->isBoolType()) { return lentypestr(t->encodedStr()); } else if(t->isArrayType()) { return "FA" + lentypestr(mangleType(t->getArrayElementType())) + std::to_string(t->toArrayType()->getArraySize()); } else if(t->isDynamicArrayType()) { return "DA" + lentypestr(mangleType(t->getArrayElementType())); } else if(t->isArraySliceType()) { return "SL" + lentypestr(mangleType(t->getArrayElementType())); } else if(t->isVoidType()) { return "v"; } else if(t->isFunctionType()) { std::string ret = "FN" + std::to_string(t->toFunctionType()->getArgumentCount()) + "FA"; for(auto a : t->toFunctionType()->getArgumentTypes()) { ret += lentypestr(mangleType(a)); } if(t->toFunctionType()->getArgumentTypes().empty()) ret += "v"; return ret; } else if(t->isStructType()) { return lentypestr(mangleScopeName(t->toStructType()->getTypeName())); } else if(t->isClassType()) { return lentypestr(mangleScopeName(t->toClassType()->getTypeName())); } else if(t->isTupleType()) { std::string ret = "ST" + std::to_string(t->toTupleType()->getElementCount()) + "SM"; for(auto m : t->toTupleType()->getElements()) ret += lentypestr(mangleType(m)); return ret; } else if(t->isPointerType()) { return "PT" + lentypestr(mangleType(t->getPointerElementType())); } else if(t->isStringType()) { return "SR"; } else if(t->isCharType()) { return "CH"; } else if(t->isEnumType()) { return "EN" + lentypestr(mangleType(t->toEnumType()->getCaseType())) + lentypestr(mangleScopeName(t->toEnumType()->getTypeName())); } else if(t->isAnyType()) { return "AY"; } else { _error_and_exit("unsupported ir type??? ('%s')\n", t); } } static std::string mangleName(const Name& id, bool includeScope) { if(id.kind == NameKind::Name || id.kind == NameKind::Type) { std::string scp; if(includeScope) scp += mangleScopeOnly(id); if(includeScope && id.scope.size() > 0) scp += std::to_string(id.name.length()); return scp + id.name; } else if(!includeScope) { if(id.kind == NameKind::Function) { std::string ret = id.name + "("; if(id.params.empty()) { ret += ")"; } else { for(auto t : id.params) ret += t->str() + ","; ret = ret.substr(0, ret.length() - 1); ret += ")"; } return ret; } else { _error_and_exit("invalid\n"); } } else { std::string ret = "_F"; if(id.kind == NameKind::Function) ret += "F"; else if(id.kind == NameKind::Type) ret += "T"; else ret += "U"; if(includeScope) ret += mangleScopeOnly(id); ret += lentypestr(id.name); if(id.kind == NameKind::Function) { ret += "_FA"; for(auto t : id.params) ret += "_" + mangleType(t); if(id.params.empty()) ret += "v"; } return ret; } } std::string Name::str() const { std::string ret = zfu::join(this->scope, "."); ret += this->name; if(this->kind == NameKind::Function) { ret += "("; for(const auto& p : this->params) ret += p->str() + ", "; if(this->params.size() > 0) ret.pop_back(), ret.pop_back(); ret += ")"; } return ret; } std::string Name::mangled() const { return mangleName(*this, true); } std::string Name::mangledWithoutScope() const { return mangleName(*this, false); } std::string obfuscateName(const std::string& name) { return zpr::sprint("__#%s", name); } std::string obfuscateName(const std::string& name, size_t id) { return zpr::sprint("__#%s_%d", name, id); } std::string obfuscateName(const std::string& name, const std::string& extra) { return zpr::sprint("__#%s_%s", name, extra); } Name Name::obfuscate(const std::string& name, NameKind kind) { return Name(kind, obfuscateName(name), { }, { }, nullptr); } Name Name::obfuscate(const std::string& name, size_t id, NameKind kind) { return Name(kind, obfuscateName(name, id), { }, { }, nullptr); } Name Name::obfuscate(const std::string& name, const std::string& extra, NameKind kind) { return Name(kind, obfuscateName(name, extra), { }, { }, nullptr); } } namespace zpr { std::string print_formatter::print(const fir::Name& x, const format_args& args) { return x.str(); } } ================================================ FILE: source/fir/Types/ArraySliceType.cpp ================================================ // ArraySliceType.cpp // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #include "ir/type.h" #include "errors.h" namespace fir { ArraySliceType::ArraySliceType(Type* elmType, bool mut) : Type(TypeKind::ArraySlice) { this->isSliceMutable = mut; this->arrayElementType = elmType; this->isVariadic = false; } Type* ArraySliceType::getElementType() { return this->arrayElementType; } bool ArraySliceType::isMutable() { return this->isSliceMutable; } Type* ArraySliceType::getDataPointerType() { if(this->isSliceMutable) return this->arrayElementType->getMutablePointerTo(); else return this->arrayElementType->getPointerTo(); } std::string ArraySliceType::str() { if(this->isCharSliceType()) return (this->isSliceMutable ? "mut str" : "str"); else return strprintf("[%s%s:%s]", this->isSliceMutable ? "mut " : "", this->arrayElementType->str(), this->isVariadic ? " ..." : ""); } std::string ArraySliceType::encodedStr() { if(this->isCharSliceType()) return (this->isSliceMutable ? "mut str" : "str"); else return strprintf("[%s%s:%s]", this->isSliceMutable ? "mut " : "", this->arrayElementType->encodedStr(), this->isVariadic ? " ..." : ""); } bool ArraySliceType::isTypeEqual(Type* other) { if(other->kind != TypeKind::ArraySlice) return false; auto af = other->toArraySliceType(); return this->arrayElementType->isTypeEqual(af->arrayElementType) && (this->isSliceMutable == af->isSliceMutable) && (this->isVariadic == af->isVariadic); } bool ArraySliceType::isVariadicType() { return this->isVariadic; } ArraySliceType* ArraySliceType::get(Type* elementType, bool mut) { return TypeCache::get().getOrAddCachedType(new ArraySliceType(elementType, mut)); } ArraySliceType* ArraySliceType::getMutable(Type* elementType) { return get(elementType, true); } ArraySliceType* ArraySliceType::getImmutable(Type* elementType) { return get(elementType, false); } ArraySliceType* ArraySliceType::getVariadic(Type* elementType) { auto a = new ArraySliceType(elementType, false); a->isVariadic = true; return TypeCache::get().getOrAddCachedType(a); } fir::Type* ArraySliceType::substitutePlaceholders(const util::hash_map& subst) { return ArraySliceType::get(this->arrayElementType->substitutePlaceholders(subst), this->isSliceMutable); } } ================================================ FILE: source/fir/Types/ArrayType.cpp ================================================ // Type.cpp // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #include "ir/type.h" namespace fir { ArrayType::ArrayType(Type* elm, size_t num) : Type(TypeKind::Array) { this->arrayElementType = elm; this->arraySize = num; } ArrayType* ArrayType::get(Type* elementType, size_t num) { return TypeCache::get().getOrAddCachedType(new ArrayType(elementType, num)); } std::string ArrayType::str() { return strprintf("[%s: %d]", this->arrayElementType->str(), this->getArraySize()); } std::string ArrayType::encodedStr() { return strprintf("[%s: %d]", this->arrayElementType->encodedStr(), this->getArraySize()); } bool ArrayType::isTypeEqual(Type* other) { if(other->kind != TypeKind::Array) return false; auto af = other->toArrayType(); return this->arrayElementType->isTypeEqual(af->arrayElementType) && (this->arraySize == af->arraySize); } // array stuff Type* ArrayType::getElementType() { return this->arrayElementType; } size_t ArrayType::getArraySize() { return this->arraySize; } fir::Type* ArrayType::substitutePlaceholders(const util::hash_map& subst) { return ArrayType::get(this->arrayElementType->substitutePlaceholders(subst), this->arraySize); } } ================================================ FILE: source/fir/Types/ClassType.cpp ================================================ // ClassType.cpp // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #include "errors.h" #include "ir/type.h" #include "ir/function.h" namespace fir { // structs ClassType::ClassType(const Name& name, const std::vector>& mems, const std::vector& methods, const std::vector& inits) : Type(TypeKind::Class), className(name) { this->setMembers(mems); this->setMethods(methods); this->setInitialiserFunctions(inits); } static util::hash_map typeCache; ClassType* ClassType::create(const Name& name, const std::vector>& members, const std::vector& methods, const std::vector& inits) { if(auto it = typeCache.find(name); it != typeCache.end()) error("class with name '%s' already exists", name.str()); else return (typeCache[name] = new ClassType(name, members, methods, inits)); } ClassType* ClassType::createWithoutBody(const Name& name) { return ClassType::create(name, { }, { }, { }); } // various std::string ClassType::str() { return "class(" + this->className.name + ")"; } std::string ClassType::encodedStr() { return this->className.str(); } bool ClassType::isTypeEqual(Type* other) { if(other->kind != TypeKind::Class) return false; return this->className == other->toClassType()->className; } // struct stuff Name ClassType::getTypeName() { return this->className; } size_t ClassType::getElementCount() { return this->typeList.size(); } Type* ClassType::getElement(const std::string& name) { auto cls = this; while(cls->classMembers.find(name) == cls->classMembers.end()) cls = cls->baseClass; iceAssert(cls && "no such member"); return cls->classMembers[name]; } size_t ClassType::getAbsoluteElementIndex(const std::string& name) { auto cls = this; while(cls->classMembers.find(name) == cls->classMembers.end()) cls = cls->baseClass; iceAssert(cls && "no such member"); return cls->indexMap[name]; } void ClassType::setMembers(const std::vector>& members) { size_t i = 0; { auto cls = this->baseClass; while(cls) { i += cls->getElementCount(); cls = cls->baseClass; } } for(const auto& [ name, ty ] : members) { this->classMembers[name] = ty; this->indexMap[name] = i; this->nameList.push_back(name); this->typeList.push_back(ty); i++; } } bool ClassType::hasElementWithName(const std::string& name) { auto cls = this; while(cls && cls->classMembers.find(name) == cls->classMembers.end()) cls = cls->baseClass; return cls != 0; } const std::vector& ClassType::getElements() { return this->typeList; } const std::vector& ClassType::getNameList() { return this->nameList; } std::vector ClassType::getAllElementsIncludingBase() { std::vector ret; std::function*)> addMembers = [&addMembers](ClassType* cls, std::vector* mems) -> void { if(!cls) return; addMembers(cls->getBaseClass(), mems); for(auto f : cls->getElements()) mems->push_back(f); }; addMembers(this, &ret); return ret; } const util::hash_map& ClassType::getElementNameMap() { return this->indexMap; } const std::vector& ClassType::getInitialiserFunctions() { return this->initialiserList; } void ClassType::setDestructor(Function* f) { this->destructor = f; } void ClassType::setCopyConstructor(Function* f) { this->copyConstructor = f; } void ClassType::setMoveConstructor(Function* f) { this->moveConstructor = f; } Function* ClassType::getDestructor() { return this->destructor; } Function* ClassType::getCopyConstructor() { return this->copyConstructor; } Function* ClassType::getMoveConstructor() { return this->moveConstructor; } const std::vector& ClassType::getMethods() { return this->methodList; } std::vector ClassType::getMethodsWithName(const std::string& id) { auto l = this->classMethodMap[id]; std::vector ret; ret.reserve(l.size()); for(auto f : l) ret.push_back(f); return ret; } Function* ClassType::getMethodWithType(FunctionType* ftype) { for(auto f : this->methodList) { if(f->getType() == ftype) return f; } error("no method with type '%s'", ftype); } bool ClassType::hasParent(Type* base) { auto target = dcast(ClassType, base); if(!target) return false; auto cls = this; while(cls) { if(target == cls) return true; cls = cls->baseClass; } return false; } void ClassType::setMethods(const std::vector& methods) { for(auto m : methods) { this->methodList.push_back(m); this->classMethodMap[m->getName().name].push_back(m); } } void ClassType::setInitialiserFunctions(const std::vector& inits) { for(auto m : inits) { this->initialiserList.push_back(m); this->classMethodMap[m->getName().name].push_back(m); } } void ClassType::addTraitImpl(TraitType* trt) { if(zfu::contains(this->implTraits, trt)) error("'%s' already implements trait '%s'", this, trt); this->implTraits.push_back(trt); } bool ClassType::implementsTrait(TraitType* trt) { return zfu::contains(this->implTraits, trt); } std::vector ClassType::getImplementedTraits() { return this->implTraits; } ClassType* ClassType::getBaseClass() { return this->baseClass; } void ClassType::setBaseClass(ClassType* ty) { this->baseClass = ty; //* keeps things simple. iceAssert(this->virtualMethodMap.empty() || !"cannot set base class after adding virtual methods"); this->virtualMethodMap = this->baseClass->virtualMethodMap; this->virtualMethodCount = this->baseClass->virtualMethodCount; this->reverseVirtualMethodMap = this->baseClass->reverseVirtualMethodMap; } void ClassType::addVirtualMethod(Function* method) { //* note: the 'reverse' virtual method map is to allow us, at translation time, to easily create the vtable without //* unnecessary searching. When we set a base class, we copy its 'reverse' map; thus, if we don't override anything, //* our vtable will just refer to the methods in the base class. //* but if we do override something, we just set the method in our 'reverse' map, which is what we'll use to build //* the vtable. simple? auto list = zfu::drop(method->getType()->toFunctionType()->getArgumentTypes(), 1); // check every member of the current mapping -- not the fastest method i admit. bool found = false; for(const auto& vm : this->virtualMethodMap) { if(vm.first.first == method->getName().name && areTypeListsContravariant(vm.first.second, list, /* trait checking: */ false)) { found = true; this->virtualMethodMap[{ method->getName().name, list }] = vm.second; this->reverseVirtualMethodMap[vm.second] = method; break; } } if(!found) { // just make a new one. this->virtualMethodMap[{ method->getName().name, list }] = this->virtualMethodCount; this->reverseVirtualMethodMap[this->virtualMethodCount] = method; this->virtualMethodCount++; } } size_t ClassType::getVirtualMethodIndex(const std::string& name, FunctionType* ft) { auto withoutself = [](std::vector p) -> std::vector { p.erase(p.begin()); return p; }; auto list = ft->getArgumentTypes(); if(auto it = this->virtualMethodMap.find({ name, withoutself(list) }); it != this->virtualMethodMap.end()) { return it->second; } else { error("no method named '%s' matching signature '%s' in virtual method table of class '%s'", name, ft, this->getTypeName().name); } } size_t ClassType::getVirtualMethodCount() { return this->virtualMethodCount; } Function* ClassType::getInlineInitialiser() { return this->inlineInitialiser; } void ClassType::setInlineInitialiser(Function* fn) { this->inlineInitialiser = fn; } Function* ClassType::getInlineDestructor() { return this->inlineDestructor; } void ClassType::setInlineDestructor(Function* fn) { this->inlineDestructor = fn; } fir::Type* ClassType::substitutePlaceholders(const util::hash_map& subst) { if(this->containsPlaceholders()) error("not supported!"); return this; } } ================================================ FILE: source/fir/Types/DynamicArrayType.cpp ================================================ // DynamicArrayType.cpp // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #include "ir/type.h" #include "errors.h" namespace fir { DynamicArrayType::DynamicArrayType(Type* elmType) : Type(TypeKind::DynamicArray) { this->arrayElementType = elmType; } Type* DynamicArrayType::getElementType() { return this->arrayElementType; } std::string DynamicArrayType::str() { return strprintf("[%s]", this->arrayElementType->str()); } std::string DynamicArrayType::encodedStr() { return strprintf("[%s]", this->arrayElementType->encodedStr()); } bool DynamicArrayType::isTypeEqual(Type* other) { if(other->kind != TypeKind::DynamicArray) return false; return this->arrayElementType->isTypeEqual(other->toDynamicArrayType()->arrayElementType); } DynamicArrayType* DynamicArrayType::get(Type* elementType) { return TypeCache::get().getOrAddCachedType(new DynamicArrayType(elementType)); } fir::Type* DynamicArrayType::substitutePlaceholders(const util::hash_map& subst) { return DynamicArrayType::get(this->arrayElementType->substitutePlaceholders(subst)); } } ================================================ FILE: source/fir/Types/EnumType.cpp ================================================ // EnumType.cpp // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #include "ir/type.h" #include "ir/value.h" #include "ir/constant.h" namespace fir { EnumType::EnumType(const Name& name, Type* ct) : Type(TypeKind::Enum), typeName(name) { this->caseType = ct; } Name EnumType::getTypeName() { return this->typeName; } Type* EnumType::getCaseType() { return this->caseType; } std::string EnumType::str() { return "enum(" + this->typeName.name + ")"; } std::string EnumType::encodedStr() { return this->typeName.str(); } bool EnumType::isTypeEqual(Type* other) { if(other->kind != TypeKind::Enum) return false; return (this->typeName == other->toEnumType()->typeName) && (this->caseType->isTypeEqual(other->toEnumType()->caseType)); } fir::ConstantValue* EnumType::getNameArray() { return this->runtimeNameArray; } fir::ConstantValue* EnumType::getCaseArray() { return this->runtimeCasesArray; } void EnumType::setNameArray(ConstantValue* arr) { this->runtimeNameArray = arr; } void EnumType::setCaseArray(ConstantValue* arr) { this->runtimeCasesArray = arr; } void EnumType::setCaseType(Type* t) { if(!this->caseType->isVoidType()) error("cannot modify enum type! was previously '%s'", this->caseType); this->caseType = t; } static util::hash_map typeCache; EnumType* EnumType::get(const Name& name, Type* caseType) { if(auto it = typeCache.find(name); it != typeCache.end()) error("enum with name '%s' already exists", name.str()); else return (typeCache[name] = new EnumType(name, caseType)); } fir::Type* EnumType::substitutePlaceholders(const util::hash_map& subst) { if(this->containsPlaceholders()) error("not supported!"); return this; } } ================================================ FILE: source/fir/Types/FunctionType.cpp ================================================ // FunctionType.cpp // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #include "ir/type.h" #include "ir/function.h" namespace Codegen { std::string unwrapPointerType(const std::string&, int*); } namespace fir { FunctionType::FunctionType(const std::vector& args, Type* ret, bool iscva) : Type(TypeKind::Function) { this->functionParams = args; this->functionRetType = ret; this->isFnCStyleVarArg = iscva; } // functions FunctionType* FunctionType::getCVariadicFunc(const std::vector& args, Type* ret) { return TypeCache::get().getOrAddCachedType(new FunctionType(args, ret, true)); } FunctionType* FunctionType::getCVariadicFunc(const std::initializer_list& args, Type* ret) { return FunctionType::getCVariadicFunc(std::vector(args.begin(), args.end()), ret); } FunctionType* FunctionType::get(const std::vector& args, Type* ret) { return TypeCache::get().getOrAddCachedType(new FunctionType(args, ret, false)); } FunctionType* FunctionType::get(const std::initializer_list& args, Type* ret) { return FunctionType::get(std::vector(args.begin(), args.end()), ret); } // various std::string FunctionType::str() { std::string ret; for(auto p : this->functionParams) ret += p->str() + ", "; if(ret.length() > 0) ret = ret.substr(0, ret.length() - 2); // remove extra comma iceAssert(this->functionRetType); return "fn(" + ret + ") -> " + this->functionRetType->str(); } std::string FunctionType::encodedStr() { return this->str(); } // function stuff const std::vector& FunctionType::getArgumentTypes() { return this->functionParams; } size_t FunctionType::getArgumentCount() { return this->functionParams.size(); } Type* FunctionType::getArgumentN(size_t n) { return this->functionParams[n]; } Type* FunctionType::getReturnType() { return this->functionRetType; } bool FunctionType::isCStyleVarArg() { return this->isFnCStyleVarArg; } bool FunctionType::isVariadicFunc() { return this->functionParams.size() > 0 && this->functionParams.back()->isArraySliceType() && this->functionParams.back()->toArraySliceType()->isVariadicType(); } bool FunctionType::isTypeEqual(Type* other) { if(other->kind != TypeKind::Function) return false; auto of = other->toFunctionType(); auto ret = (this->isFnCStyleVarArg == of->isFnCStyleVarArg) && (this->functionRetType == of->functionRetType) && (this->functionParams.size() == of->functionParams.size()); if(ret) { for(size_t i = 0; i < this->functionParams.size(); i++) { if(this->functionParams[i] != of->functionParams[i]) return false; } return true; } else { return false; } } fir::Type* FunctionType::substitutePlaceholders(const util::hash_map& subst) { auto args = zfu::map(this->functionParams, [&subst](auto t) -> auto { return t->substitutePlaceholders(subst); }); auto ret = this->functionRetType->substitutePlaceholders(subst); if(this->isFnCStyleVarArg) return FunctionType::getCVariadicFunc(args, ret); else return FunctionType::get(args, ret); } } ================================================ FILE: source/fir/Types/OpaqueType.cpp ================================================ // OpaqueType.cpp // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. #include "ir/type.h" #include "ir/value.h" #include "ir/constant.h" namespace fir { OpaqueType::OpaqueType(const std::string& name, size_t size) : Type(TypeKind::Opaque) { this->typeName = name; this->typeSizeInBits = size; } std::string OpaqueType::str() { return strprintf("opaque(%s)", this->typeName); } std::string OpaqueType::encodedStr() { return strprintf("opaque(%s)", this->typeName); } bool OpaqueType::isTypeEqual(Type* other) { return other && other->isOpaqueType() && other->toOpaqueType()->typeName == this->typeName; } fir::Type* OpaqueType::substitutePlaceholders(const util::hash_map& subst) { return this; } static util::hash_map typeCache; OpaqueType* OpaqueType::get(const std::string& name, size_t size) { if(size < 8) error("types must be >= 8 bits (for now) (%s)", name); if(auto it = typeCache.find(name); it != typeCache.end()) return it->second; else return (typeCache[name] = new OpaqueType(name, size)); } } ================================================ FILE: source/fir/Types/PointerType.cpp ================================================ // Type.cpp // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #include "ir/type.h" namespace fir { PointerType::PointerType(Type* base, bool mut) : Type(TypeKind::Pointer) { this->baseType = base; this->isPtrMutable = mut; } PointerType* PointerType::getMutable() { if(this->isPtrMutable) return this; return this->baseType->getMutablePointerTo()->toPointerType(); } PointerType* PointerType::getImmutable() { if(!this->isPtrMutable) return this; return this->baseType->getPointerTo()->toPointerType(); } bool PointerType::isMutable() { return this->isPtrMutable; } PointerType* PointerType::getInt8Ptr() { return Type::getInt8()->getPointerTo()->toPointerType(); } PointerType* PointerType::getInt16Ptr() { return Type::getInt16()->getPointerTo()->toPointerType(); } PointerType* PointerType::getInt32Ptr() { return Type::getInt32()->getPointerTo()->toPointerType(); } PointerType* PointerType::getInt64Ptr() { return Type::getInt64()->getPointerTo()->toPointerType(); } PointerType* PointerType::getInt128Ptr() { return Type::getInt128()->getPointerTo()->toPointerType(); } PointerType* PointerType::getUint8Ptr() { return Type::getUint8()->getPointerTo()->toPointerType(); } PointerType* PointerType::getUint16Ptr() { return Type::getUint16()->getPointerTo()->toPointerType(); } PointerType* PointerType::getUint32Ptr() { return Type::getUint32()->getPointerTo()->toPointerType(); } PointerType* PointerType::getUint64Ptr() { return Type::getUint64()->getPointerTo()->toPointerType(); } PointerType* PointerType::getUint128Ptr() { return Type::getUint128()->getPointerTo()->toPointerType(); } // various std::string PointerType::str() { return (this->isPtrMutable ? "&mut " : "&") + this->baseType->str(); } std::string PointerType::encodedStr() { return this->baseType->encodedStr() + (this->isPtrMutable ? "MP" : "P"); } bool PointerType::isTypeEqual(Type* other) { if(other->kind != TypeKind::Pointer) return false; auto op = other->toPointerType(); return this->baseType->isTypeEqual(op->baseType) && (this->isPtrMutable == op->isPtrMutable); } fir::Type* PointerType::substitutePlaceholders(const util::hash_map& subst) { auto base = this->baseType->substitutePlaceholders(subst); if(this->isMutable()) return base->getMutablePointerTo(); else return base->getPointerTo(); } } ================================================ FILE: source/fir/Types/PrimitiveType.cpp ================================================ // Type.cpp // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #include "ir/type.h" namespace fir { PrimitiveType::PrimitiveType(size_t bits, bool issigned, Kind kind) : Type(TypeKind::Primitive) { this->bitWidth = bits; this->primKind = kind; this->isTypeSigned = issigned; } static util::hash_map> primitiveTypeCache; PrimitiveType* PrimitiveType::getIntWithBitWidthAndSignage(size_t bits, bool issigned) { std::vector& types = primitiveTypeCache[bits]; for(auto t : types) { iceAssert(t->bitWidth == bits); if(t->isIntegerType() && !t->isFloatingPointType() && (t->isSigned() == issigned)) return t; } return *types.insert(types.end(), new PrimitiveType(bits, issigned, Kind::Integer)); } PrimitiveType* PrimitiveType::getFloatWithBitWidth(size_t bits) { std::vector& types = primitiveTypeCache[bits]; for(auto t : types) { iceAssert(t->bitWidth == bits); if(t->isFloatingPointType()) return t; } return *types.insert(types.end(), new PrimitiveType(bits, false, Kind::Floating)); } PrimitiveType* PrimitiveType::getIntN(size_t bits) { return PrimitiveType::getIntWithBitWidthAndSignage(bits, true); } PrimitiveType* PrimitiveType::getUintN(size_t bits) { return PrimitiveType::getIntWithBitWidthAndSignage(bits, false); } PrimitiveType* PrimitiveType::getInt8() { return PrimitiveType::getIntWithBitWidthAndSignage(8, true); } PrimitiveType* PrimitiveType::getInt16() { return PrimitiveType::getIntWithBitWidthAndSignage(16, true); } PrimitiveType* PrimitiveType::getInt32() { return PrimitiveType::getIntWithBitWidthAndSignage(32, true); } PrimitiveType* PrimitiveType::getInt64() { return PrimitiveType::getIntWithBitWidthAndSignage(64, true); } PrimitiveType* PrimitiveType::getInt128() { return PrimitiveType::getIntWithBitWidthAndSignage(128, true); } PrimitiveType* PrimitiveType::getUint8() { return PrimitiveType::getIntWithBitWidthAndSignage(8, false); } PrimitiveType* PrimitiveType::getUint16() { return PrimitiveType::getIntWithBitWidthAndSignage(16, false); } PrimitiveType* PrimitiveType::getUint32() { return PrimitiveType::getIntWithBitWidthAndSignage(32, false); } PrimitiveType* PrimitiveType::getUint64() { return PrimitiveType::getIntWithBitWidthAndSignage(64, false); } PrimitiveType* PrimitiveType::getUint128() { return PrimitiveType::getIntWithBitWidthAndSignage(128, false); } PrimitiveType* PrimitiveType::getFloat32() { return PrimitiveType::getFloatWithBitWidth(32); } PrimitiveType* PrimitiveType::getFloat64() { return PrimitiveType::getFloatWithBitWidth(64); } PrimitiveType* PrimitiveType::getFloat128() { return PrimitiveType::getFloatWithBitWidth(128); } // various std::string PrimitiveType::str() { // is primitive. std::string ret; if(this->primKind == Kind::Integer) { if(this->isSigned()) ret = "i"; else ret = "u"; ret += std::to_string(this->getIntegerBitWidth()); } else if(this->primKind == Kind::Floating) { ret = "f" + std::to_string(this->getFloatingPointBitWidth()); } else { iceAssert(0); } return ret; } std::string PrimitiveType::encodedStr() { return this->str(); } bool PrimitiveType::isTypeEqual(Type* other) { if(other->kind != TypeKind::Primitive) return false; auto op = other->toPrimitiveType(); return (this->primKind == op->primKind) && (this->bitWidth == op->bitWidth) && (this->isTypeSigned == op->isTypeSigned); } bool PrimitiveType::isSigned() { iceAssert(this->primKind == Kind::Integer && "not integer type"); return this->isTypeSigned; } size_t PrimitiveType::getIntegerBitWidth() { iceAssert(this->primKind == Kind::Integer && "not integer type"); return this->bitWidth; } // float stuff size_t PrimitiveType::getFloatingPointBitWidth() { iceAssert(this->primKind == Kind::Floating && "not floating point type"); return this->bitWidth; } PrimitiveType* PrimitiveType::getOppositeSignedType() { if(this == Type::getInt8()) { return Type::getUint8(); } else if(this == Type::getInt16()) { return Type::getUint16(); } else if(this == Type::getInt32()) { return Type::getUint32(); } else if(this == Type::getInt64()) { return Type::getUint64(); } else if(this == Type::getInt128()) { return Type::getUint128(); } else if(this == Type::getUint8()) { return Type::getInt8(); } else if(this == Type::getUint16()) { return Type::getInt16(); } else if(this == Type::getUint32()) { return Type::getInt32(); } else if(this == Type::getUint64()) { return Type::getInt64(); } else if(this == Type::getUint128()) { return Type::getInt128(); } else { return this; } } fir::Type* PrimitiveType::substitutePlaceholders(const util::hash_map& subst) { return this; } } ================================================ FILE: source/fir/Types/RawUnionType.cpp ================================================ // RawUnionType.cpp // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. #include "errors.h" #include "ir/type.h" #include "pts.h" namespace fir { // structs RawUnionType::RawUnionType(const Name& name, const util::hash_map& mems) : Type(TypeKind::RawUnion), unionName(name) { this->setBody(mems); } static util::hash_map typeCache; RawUnionType* RawUnionType::create(const Name& name, const util::hash_map& mems) { if(auto it = typeCache.find(name); it != typeCache.end()) error("union with name '%s' already exists", name.str()); else return (typeCache[name] = new RawUnionType(name, mems)); } RawUnionType* RawUnionType::createWithoutBody(const Name& name) { return RawUnionType::create(name, { }); } // various std::string RawUnionType::str() { return "raw_union(" + this->unionName.name + ")"; } std::string RawUnionType::encodedStr() { return this->unionName.str(); } bool RawUnionType::isTypeEqual(Type* other) { if(other->kind != TypeKind::Union) return false; return (this->unionName == other->toRawUnionType()->unionName); } // struct stuff Name RawUnionType::getTypeName() { return this->unionName; } size_t RawUnionType::getVariantCount() { return this->variants.size(); } const util::hash_map& RawUnionType::getVariants() { return this->variants; } bool RawUnionType::hasVariant(const std::string& name) { return this->variants.find(name) != this->variants.end(); } Type* RawUnionType::getVariant(const std::string& name) { if(auto it = this->variants.find(name); it != this->variants.end()) return it->second; else error("no variant named '%s' in union '%s'", name, this->getTypeName().str()); } void RawUnionType::setBody(const util::hash_map& members) { this->variants = members; } fir::Type* RawUnionType::substitutePlaceholders(const util::hash_map& subst) { if(this->containsPlaceholders()) error("not supported!"); return this; } } ================================================ FILE: source/fir/Types/SingleTypes.cpp ================================================ // SingleTypes.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "errors.h" #include "ir/type.h" namespace fir { using PolySubst = util::hash_map; static AnyType* singleAny = 0; AnyType::AnyType() : Type(TypeKind::Any) { } std::string AnyType::str() { return "any"; } std::string AnyType::encodedStr() { return "any"; } bool AnyType::isTypeEqual(Type* other) { return other && other->isAnyType(); } AnyType* AnyType::get() { return singleAny = (singleAny ? singleAny : new AnyType()); } fir::Type* AnyType::substitutePlaceholders(const PolySubst&) { return this; } static BoolType* singleBool = 0; BoolType::BoolType() : Type(TypeKind::Bool) { } std::string BoolType::str() { return "bool"; } std::string BoolType::encodedStr() { return "bool"; } bool BoolType::isTypeEqual(Type* other) { return other && other->isBoolType(); } BoolType* BoolType::get() { return singleBool = (singleBool ? singleBool : new BoolType()); } fir::Type* BoolType::substitutePlaceholders(const PolySubst&) { return this; } static VoidType* singleVoid = 0; VoidType::VoidType() : Type(TypeKind::Void) { } std::string VoidType::str() { return "void"; } std::string VoidType::encodedStr() { return "void"; } bool VoidType::isTypeEqual(Type* other) { return other && other->isVoidType(); } VoidType* VoidType::get() { return singleVoid = (singleVoid ? singleVoid : new VoidType()); } fir::Type* VoidType::substitutePlaceholders(const PolySubst&) { return this; } static NullType* singleNull = 0; NullType::NullType() : Type(TypeKind::Null) { } std::string NullType::str() { return "nulltype"; } std::string NullType::encodedStr() { return "nulltype"; } bool NullType::isTypeEqual(Type* other) { return other && other->isNullType(); } NullType* NullType::get() { return singleNull = (singleNull ? singleNull : new NullType()); } fir::Type* NullType::substitutePlaceholders(const PolySubst&) { return this; } static RangeType* singleRange = 0; RangeType::RangeType() : Type(TypeKind::Range) { } std::string RangeType::str() { return "range"; } std::string RangeType::encodedStr() { return "range"; } bool RangeType::isTypeEqual(Type* other) { return other && other->isRangeType(); } RangeType* RangeType::get() { return singleRange = (singleRange ? singleRange : new RangeType()); } fir::Type* RangeType::substitutePlaceholders(const PolySubst&) { return this; } static StringType* singleString = 0; StringType::StringType() : Type(TypeKind::String) { } std::string StringType::str() { return "string"; } std::string StringType::encodedStr() { return "string"; } bool StringType::isTypeEqual(Type* other) { return other && other->isStringType(); } StringType* StringType::get() { return singleString = (singleString ? singleString : new StringType()); } fir::Type* StringType::substitutePlaceholders(const PolySubst&) { return this; } std::string ConstantNumberType::encodedStr() { return "number"; } bool ConstantNumberType::isSigned() { return this->_signed; } bool ConstantNumberType::isFloating() { return this->_floating; } size_t ConstantNumberType::getMinBits() { return this->_bits; } bool ConstantNumberType::isTypeEqual(Type* other) { return other && other->isConstantNumberType() && other->toConstantNumberType()->_bits == this->_bits && other->toConstantNumberType()->_signed == this->_signed && other->toConstantNumberType()->_floating == this->_floating; } ConstantNumberType* ConstantNumberType::get(bool neg, bool flt, size_t bits) { return TypeCache::get().getOrAddCachedType(new ConstantNumberType(neg, flt, bits)); } ConstantNumberType::ConstantNumberType(bool neg, bool flt, size_t bits) : Type(TypeKind::ConstantNumber) { this->_bits = bits; this->_signed = neg; this->_floating = flt; } fir::Type* ConstantNumberType::substitutePlaceholders(const PolySubst& subst) { return this; } std::string ConstantNumberType::str() { // return strprintf("number(sgn: %s, flt: %s, bits: %d)", _signed, _floating, _bits); return strprintf("number"); } ConstantNumberType* unifyConstantTypes(ConstantNumberType* a, ConstantNumberType* b) { auto sgn = a->isSigned() || b->isSigned(); auto flt = a->isFloating() || b->isFloating(); auto bit = std::max(a->getMinBits(), b->getMinBits()); return ConstantNumberType::get(sgn, flt, bit); } Type* getBestFitTypeForConstant(ConstantNumberType* cnt) { if(cnt->isFloating()) { if(cnt->getMinBits() > 64) error("constant number type '%s' requires too many bits", cnt); return fir::Type::getFloat64(); } else { if(cnt->getMinBits() < fir::Type::getNativeWord()->getBitWidth()) { return fir::Type::getNativeWord(); } else if(cnt->isSigned()) { error("constant number type '%s' requires too many bits", cnt); } else { if(cnt->getMinBits() > fir::Type::getNativeUWord()->getBitWidth()) error("constant number type '%s' requires too many bits", cnt); return fir::Type::getNativeUWord(); } } } std::string PolyPlaceholderType::str() { return strprintf("$%s/%d", this->name, this->group); } std::string PolyPlaceholderType::encodedStr() { return strprintf("$%s/%d", this->name, this->group); } std::string PolyPlaceholderType::getName() { return this->name; } int PolyPlaceholderType::getGroup() { return this->group; } static std::vector> cache; PolyPlaceholderType* PolyPlaceholderType::get(const std::string& n, int group) { while(static_cast(group) >= cache.size()) cache.push_back({ }); if(auto it = cache[group].find(n); it != cache[group].end()) return it->second; return cache[group][n] = new PolyPlaceholderType(n, group); } bool PolyPlaceholderType::isTypeEqual(Type* other) { // return other && other->isPolyPlaceholderType() && other->toPolyPlaceholderType()->name == this->name // && other->toPolyPlaceholderType()->group == this->group; //! ACHTUNG ! // performance optimisation: since all polys go through ::get, and we already guarantee interning // from that function, we should be able to just compare pointers. return (other == this); } PolyPlaceholderType::PolyPlaceholderType(const std::string& n, int g) : Type(TypeKind::PolyPlaceholder) { this->name = n; this->group = g; } static fir::Type* _substitute(const PolySubst& subst, fir::Type* t) { if(auto it = subst.find(t); it != subst.end()) return it->second->substitutePlaceholders(subst); return t; } fir::Type* PolyPlaceholderType::substitutePlaceholders(const PolySubst& subst) { return _substitute(subst, this); } } ================================================ FILE: source/fir/Types/StructType.cpp ================================================ // StructType.cpp // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #include "errors.h" #include "ir/type.h" #include "pts.h" namespace fir { // structs StructType::StructType(const Name& name, const std::vector>& mems, bool ispacked) : Type(TypeKind::Struct), structName(name) { this->isTypePacked = ispacked; this->setBody(mems); } static util::hash_map typeCache; StructType* StructType::create(const Name& name, const std::vector>& members, bool packed) { if(auto it = typeCache.find(name); it != typeCache.end()) error("struct with name '%s' already exists", name.str()); else return (typeCache[name] = new StructType(name, members, packed)); } StructType* StructType::createWithoutBody(const Name& name, bool isPacked) { return StructType::create(name, { }, isPacked); } // various std::string StructType::str() { return "struct(" + this->structName.name + ")"; } std::string StructType::encodedStr() { return this->structName.str(); } bool StructType::isTypeEqual(Type* other) { if(other->kind != TypeKind::Struct) return false; return (this->structName == other->toStructType()->structName) && (this->isTypePacked == other->toStructType()->isTypePacked); } // struct stuff Name StructType::getTypeName() { return this->structName; } size_t StructType::getElementCount() { return this->typeList.size(); } Type* StructType::getElementN(size_t n) { iceAssert(n < this->typeList.size() && "out of bounds"); return this->typeList[n]; } Type* StructType::getElement(const std::string& name) { iceAssert(this->structMembers.find(name) != this->structMembers.end() && "no such member"); return this->structMembers[name]; } size_t StructType::getElementIndex(const std::string& name) { iceAssert(this->structMembers.find(name) != this->structMembers.end() && "no such member"); return this->indexMap[name]; } bool StructType::hasElementWithName(const std::string& name) { return this->indexMap.find(name) != this->indexMap.end(); } const std::vector& StructType::getElements() { return this->typeList; } void StructType::addTraitImpl(TraitType* trt) { if(zfu::contains(this->implTraits, trt)) error("'%s' already implements trait '%s'", this, trt); this->implTraits.push_back(trt); } bool StructType::implementsTrait(TraitType* trt) { return zfu::contains(this->implTraits, trt); } std::vector StructType::getImplementedTraits() { return this->implTraits; } const util::hash_map& StructType::getIndexMap() { return this->indexMap; } void StructType::setBody(const std::vector>& members) { size_t i = 0; for(const auto& [ name, ty ] : members) { this->structMembers[name] = ty; this->indexMap[name] = i; this->typeList.push_back(ty); i++; } } fir::Type* StructType::substitutePlaceholders(const util::hash_map& subst) { if(this->containsPlaceholders()) error("not supported!"); return this; } } ================================================ FILE: source/fir/Types/TraitType.cpp ================================================ // TraitType.cpp // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. #include "errors.h" #include "ir/type.h" #include "pts.h" namespace fir { // structs TraitType::TraitType(const Name& name, const std::vector>& meths) : Type(TypeKind::Trait), traitName(name) { this->methods = meths; } static util::hash_map typeCache; TraitType* TraitType::create(const Name& name) { if(auto it = typeCache.find(name); it != typeCache.end()) error("trait with name '%s' already exists", name.str()); else return (typeCache[name] = new TraitType(name, { })); } // various std::string TraitType::str() { return "trait(" + this->traitName.name + ")"; } std::string TraitType::encodedStr() { return this->traitName.str(); } bool TraitType::isTypeEqual(Type* other) { if(other->kind != TypeKind::Struct) return false; return (this->traitName == other->toTraitType()->traitName); } // struct stuff Name TraitType::getTypeName() { return this->traitName; } size_t TraitType::getMethodCount() { return this->methods.size(); } const std::vector>& TraitType::getMethods() { return this->methods; } void TraitType::setMethods(const std::vector>& meths) { this->methods = meths; } fir::Type* TraitType::substitutePlaceholders(const util::hash_map& subst) { if(this->containsPlaceholders()) error("not supported!"); return this; } } ================================================ FILE: source/fir/Types/TupleType.cpp ================================================ // TupleType.cpp // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #include "errors.h" #include "ir/type.h" namespace fir { TupleType::TupleType(const std::vector& mems) : Type(TypeKind::Tuple) { this->members = mems; } size_t TupleType::getElementCount() { return this->members.size(); } Type* TupleType::getElementN(size_t n) { iceAssert(n < this->members.size()); return this->members[n]; } const std::vector& TupleType::getElements() { return this->members; } std::string TupleType::str() { return strprintf("(%s)", typeListToString(this->members)); } std::string TupleType::encodedStr() { return strprintf("(%s)", typeListToString(this->members)); } bool TupleType::isTypeEqual(Type* other) { if(other->kind != TypeKind::Tuple) return false; auto ot = other->toTupleType(); return areTypeListsEqual(this->members, ot->members); } TupleType* TupleType::get(const std::vector& mems) { return TypeCache::get().getOrAddCachedType(new TupleType(mems)); } TupleType* TupleType::get(const std::initializer_list& mems) { return TupleType::get(std::vector(mems.begin(), mems.end())); } fir::Type* TupleType::substitutePlaceholders(const util::hash_map& subst) { auto args = zfu::map(this->members, [&subst](auto t) -> auto { return t->substitutePlaceholders(subst); }); return TupleType::get(members); } } ================================================ FILE: source/fir/Types/Type.cpp ================================================ // Type.cpp // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #include "errors.h" #include "ir/type.h" #include "gluecode.h" namespace pts { std::string unwrapPointerType(const std::string&, int*); } namespace fir { static TypeCache tc; TypeCache& TypeCache::get() { return tc; } static size_t nativeWordSize = 64; void setNativeWordSizeInBits(size_t sz) { if(sz < 8 || sz > 64) error("native word size must be >= 8 and < 64, %d invalid", sz); // we're not gonna check any further, anything becomes your problem once you change this. nativeWordSize = sz; } size_t getNativeWordSizeInBits() { return nativeWordSize; } int getCastDistance(Type* from, Type* to) { if(from == to) return 0; if(from->isConstantNumberType() && to->isPrimitiveType()) { auto cty = from->toConstantNumberType(); if(!cty->isFloating() && to->isIntegerType()) return 0; else if(!cty->isFloating() && to->isFloatingPointType()) return 1; else if(cty->isFloating()) // not isint means isfloat, so if we're doing float -> float the cost is 0 return 0; else // if we reach here, we're trying to do float -> int, which is a no-go. return -1; } else if(from->isIntegerType() && to->isIntegerType()) { if(from->isSignedIntType() == to->isSignedIntType()) { auto bitdiff = std::abs(static_cast(from->toPrimitiveType()->getIntegerBitWidth()) - static_cast(to->toPrimitiveType()->getIntegerBitWidth())); switch(bitdiff) { case 0: return 0; // same case 8: return 1; // i16 - i8 case 16: return 1; // i32 - i16 case 32: return 1; // i64 - i32 case 24: return 2; // i32 - i8 case 48: return 2; // i64 - i16 case 56: return 3; // i64 - i8 default: iceAssert(0); } } else { // only allow casting unsigned things to signed things... maybe?? // TODO: investigate whether we want such loose casting. //? for now, no. return -1; } } else if(from->isDynamicArrayType() && to->isArraySliceType() && from->getArrayElementType() == to->getArrayElementType()) { return 2; } else if(from->isDynamicArrayType() && from->getArrayElementType()->isVoidType() && (to->isDynamicArrayType() || to->isArraySliceType() || to->isArrayType())) { return 2; } else if(from->isFloatingPointType() && to->isFloatingPointType()) { return 1; } else if(from->isStringType() && to == fir::Type::getInt8Ptr()) { return 5; } else if(from->isStringType() && to->isCharSliceType()) { return 3; } else if(from->isCharSliceType() && to == fir::Type::getInt8Ptr()) { return 3; } else if(from->isMutablePointer() && to->isImmutablePointer() && from->getPointerElementType() == to->getPointerElementType()) { // cast from a mutable pointer type to an immutable one can be implicit. return 1; } else if(from->isVariadicArrayType() && to->isArraySliceType() && from->getArrayElementType() == to->getArrayElementType()) { // allow implicit casting from variadic slices to their normal counterparts. return 4; } else if(from->isArraySliceType() && to->isArraySliceType() && (from->getArrayElementType() == to->getArrayElementType()) && from->toArraySliceType()->isMutable() && !to->toArraySliceType()->isMutable() && !from->isVariadicArrayType() && !to->isVariadicArrayType()) { // same with slices -- cast from mutable slice to immut slice can be implicit. return 1; } //* note: we don't need to check that 'to' is a class type, because if it's not then the parent check will fail anyway. else if(from->isPointerType() && to->isPointerType() && from->getPointerElementType()->isClassType() && from->getPointerElementType()->toClassType()->hasParent(to->getPointerElementType())) { // cast from a derived class pointer to a base class pointer return 2; } else if(from->isNullType() && to->isPointerType()) { return 1; } else if(from->isTupleType() && to->isTupleType() && from->toTupleType()->getElementCount() == to->toTupleType()->getElementCount()) { int sum = 0; auto ftt = from->toTupleType(); auto ttt = to->toTupleType(); for(size_t i = 0; i < ttt->getElementCount(); i++) { if(int k = fir::getCastDistance(ftt->getElementN(i), ttt->getElementN(i)); k < 0) return -1; else sum += k; } return sum; } else if(to->isAnyType()) { // lol. completely arbitrary. return 15; } return -1; } PrimitiveType* Type::getNativeWord() { return PrimitiveType::getIntN(nativeWordSize); } PrimitiveType* Type::getNativeUWord() { return PrimitiveType::getUintN(nativeWordSize); } PointerType* Type::getNativeWordPtr() { return Type::getNativeWord()->getPointerTo()->toPointerType(); } std::string Type::typeListToString(const std::initializer_list& types, bool includeBraces) { return typeListToString(std::vector(types.begin(), types.end()), includeBraces); } std::string Type::typeListToString(const std::vector& types, bool braces) { // print types std::string str = (braces ? "{ " : ""); for(auto t : types) str += t->str() + ", "; if(str.length() > 2) str = str.substr(0, str.length() - 2); return str + (braces ? " }" : ""); } bool Type::areTypeListsEqual(const std::vector& a, const std::vector& b) { if(a.size() != b.size()) return false; if(a.size() == 0 && b.size() == 0) return true; for(size_t i = 0; i < a.size(); i++) { if(a[i] != b[i]) return false; } return true; } bool Type::areTypeListsEqual(const std::initializer_list& a, const std::initializer_list& b) { return areTypeListsEqual(std::vector(a.begin(), a.end()), std::vector(b.begin(), b.end())); } Type* Type::getPointerTo() { // cache the pointer internally if(!this->pointerTo) { PointerType* newType = new PointerType(this, false); this->pointerTo = newType; } return this->pointerTo; } Type* Type::getMutablePointerTo() { // cache the pointer internally if(!this->mutablePointerTo) { PointerType* newType = new PointerType(this, true); this->mutablePointerTo = newType; } return this->mutablePointerTo; } Type* Type::getMutablePointerVersion() { iceAssert(this->isPointerType() && "not pointer type"); return this->toPointerType()->getMutable(); } Type* Type::getImmutablePointerVersion() { iceAssert(this->isPointerType() && "not pointer type"); return this->toPointerType()->getImmutable(); } Type* Type::getPointerElementType() { if(!this->isPointerType()) error("type is not a pointer ('%s')", this); PointerType* ptrthis = this->toPointerType(); iceAssert(ptrthis); // ptrthis could only have been obtained by calling getPointerTo // on an already normalised type, so this should not be needed // newType = tc->normaliseType(newType); return ptrthis->baseType; } Type* Type::getIndirectedType(int times) { Type* ret = this; if(times > 0) { for(int i = 0; i < times; i++) ret = ret->getPointerTo(); } else if(times < 0) { for(int i = 0; i < -times; i++) ret = ret->getPointerElementType(); } // both getPointerTo and getPointerElementType should already // return normalised types // ret = tc->normaliseType(ret); return ret; } Type* Type::fromBuiltin(const std::string& builtin) { int indirections = 0; auto copy = pts::unwrapPointerType(builtin, &indirections); Type* real = 0; if(copy == INT8_TYPE_STRING) real = Type::getInt8(); else if(copy == INT16_TYPE_STRING) real = Type::getInt16(); else if(copy == INT32_TYPE_STRING) real = Type::getInt32(); else if(copy == INT64_TYPE_STRING) real = Type::getInt64(); else if(copy == INT128_TYPE_STRING) real = Type::getInt128(); else if(copy == UINT8_TYPE_STRING) real = Type::getUint8(); else if(copy == UINT16_TYPE_STRING) real = Type::getUint16(); else if(copy == UINT32_TYPE_STRING) real = Type::getUint32(); else if(copy == UINT64_TYPE_STRING) real = Type::getUint64(); else if(copy == UINT128_TYPE_STRING) real = Type::getUint128(); else if(copy == FLOAT32_TYPE_STRING) real = Type::getFloat32(); else if(copy == FLOAT64_TYPE_STRING) real = Type::getFloat64(); else if(copy == FLOAT128_TYPE_STRING) real = Type::getFloat128(); else if(copy == STRING_TYPE_STRING) real = Type::getString(); else if(copy == CHARACTER_SLICE_TYPE_STRING) real = ArraySliceType::get(Type::getInt8(), false); else if(copy == BOOL_TYPE_STRING) real = Type::getBool(); else if(copy == VOID_TYPE_STRING) real = Type::getVoid(); // unspecified things else if(copy == INTUNSPEC_TYPE_STRING) real = Type::getNativeWord(); else if(copy == UINTUNSPEC_TYPE_STRING) real = Type::getNativeUWord(); else if(copy == FLOAT_TYPE_STRING) real = Type::getFloat32(); else if(copy == DOUBLE_TYPE_STRING) real = Type::getFloat64(); else if(copy == ANY_TYPE_STRING) real = Type::getAny(); else return 0; iceAssert(real); real = real->getIndirectedType(indirections); return real; } Type* Type::getArrayElementType() { if(this->isDynamicArrayType()) return this->toDynamicArrayType()->getElementType(); else if(this->isArrayType()) return this->toArrayType()->getElementType(); else if(this->isArraySliceType()) return this->toArraySliceType()->getElementType(); else error("'%s' is not an array type", this); } size_t Type::getBitWidth() { if(this->isIntegerType()) return this->toPrimitiveType()->getIntegerBitWidth(); else if(this->isFloatingPointType()) return this->toPrimitiveType()->getFloatingPointBitWidth(); else if(this->isPointerType()) return sizeof(void*) * CHAR_BIT; else return 0; } static bool _containsPlaceholders(fir::Type* ty, std::unordered_set& seen, std::vector* found) { if(seen.find(ty) != seen.end()) return false; seen.insert(ty); if(ty->isPolyPlaceholderType()) { if(found) found->push_back(ty->toPolyPlaceholderType()); return true; } else if(ty->isPointerType()) return _containsPlaceholders(ty->getPointerElementType(), seen, found); else if(ty->isArrayType()) return _containsPlaceholders(ty->getArrayElementType(), seen, found); else if(ty->isArraySliceType()) return _containsPlaceholders(ty->getArrayElementType(), seen, found); else if(ty->isDynamicArrayType()) return _containsPlaceholders(ty->getArrayElementType(), seen, found); else if(ty->isArrayType()) return _containsPlaceholders(ty->getArrayElementType(), seen, found); else if(ty->isUnionVariantType()) return _containsPlaceholders(ty->toUnionVariantType()->getInteriorType(), seen, found); else if(ty->isTupleType()) { bool res = false; for(auto t : ty->toTupleType()->getElements()) res |= _containsPlaceholders(t, seen, found); return res; } else if(ty->isClassType()) { bool res = false; for(auto t : ty->toClassType()->getElements()) res |= _containsPlaceholders(t, seen, found); return res; } else if(ty->isStructType()) { bool res = false; for(auto t : ty->toStructType()->getElements()) res |= _containsPlaceholders(t, seen, found); return res; } else if(ty->isFunctionType()) { bool res = ty->toFunctionType()->getReturnType()->containsPlaceholders(); for(auto t : ty->toFunctionType()->getArgumentTypes()) res |= _containsPlaceholders(t, seen, found); return res; } else if(ty->isUnionType()) { bool res = false; for(const auto& t : ty->toUnionType()->getVariants()) res |= _containsPlaceholders(t.second, seen, found); return res; } else { return false; } } // better to just handle this centrally i guess. bool Type::containsPlaceholders() { std::unordered_set seen; return _containsPlaceholders(this, seen, nullptr); } std::vector Type::getContainedPlaceholders() { std::unordered_set seen; std::vector found; _containsPlaceholders(this, seen, &found); return found; } bool Type::isPointerTo(Type* other) { return other->getPointerTo() == this; } bool Type::isPointerElementOf(Type* other) { return this->getPointerTo() == other; } PrimitiveType* Type::toPrimitiveType() { if(this->kind != TypeKind::Primitive) error("not primitive type"); return static_cast(this); } FunctionType* Type::toFunctionType() { if(this->kind != TypeKind::Function) error("not function type"); return static_cast(this); } PointerType* Type::toPointerType() { if(this->kind != TypeKind::Pointer) error("not pointer type"); return static_cast(this); } StructType* Type::toStructType() { if(this->kind != TypeKind::Struct) error("not struct type"); return static_cast(this); } ClassType* Type::toClassType() { if(this->kind != TypeKind::Class) error("not class type"); return static_cast(this); } TupleType* Type::toTupleType() { if(this->kind != TypeKind::Tuple) error("not tuple type"); return static_cast(this); } ArrayType* Type::toArrayType() { if(this->kind != TypeKind::Array) error("not array type"); return static_cast(this); } DynamicArrayType* Type::toDynamicArrayType() { if(this->kind != TypeKind::DynamicArray) error("not dynamic array type"); return static_cast(this); } ArraySliceType* Type::toArraySliceType() { if(this->kind != TypeKind::ArraySlice) error("not array slice type"); return static_cast(this); } RangeType* Type::toRangeType() { if(this->kind != TypeKind::Range) error("not range type"); return static_cast(this); } StringType* Type::toStringType() { if(this->kind != TypeKind::String) error("not string type"); return static_cast(this); } EnumType* Type::toEnumType() { if(this->kind != TypeKind::Enum) error("not enum type"); return static_cast(this); } UnionType* Type::toUnionType() { if(this->kind != TypeKind::Union) error("not union type"); return static_cast(this); } RawUnionType* Type::toRawUnionType() { if(this->kind != TypeKind::RawUnion) error("not raw union type"); return static_cast(this); } AnyType* Type::toAnyType() { if(this->kind != TypeKind::Any) error("not any type"); return static_cast(this); } NullType* Type::toNullType() { if(this->kind != TypeKind::Null) error("not null type"); return static_cast(this); } ConstantNumberType* Type::toConstantNumberType() { if(this->kind != TypeKind::ConstantNumber) error("not constant number type"); return static_cast(this); } PolyPlaceholderType* Type::toPolyPlaceholderType() { if(this->kind != TypeKind::PolyPlaceholder) error("not poly placeholder type"); return static_cast(this); } UnionVariantType* Type::toUnionVariantType() { if(this->kind != TypeKind::UnionVariant) error("not union variant type"); return static_cast(this); } OpaqueType* Type::toOpaqueType() { if(this->kind != TypeKind::Opaque) error("not opaque type"); return static_cast(this); } TraitType* Type::toTraitType() { if(this->kind != TypeKind::Trait) error("not trait type"); return static_cast(this); } bool Type::isConstantNumberType() { return this->kind == TypeKind::ConstantNumber; } bool Type::isStructType() { return this->kind == TypeKind::Struct; } bool Type::isTupleType() { return this->kind == TypeKind::Tuple; } bool Type::isClassType() { return this->kind == TypeKind::Class; } bool Type::isPackedStruct() { return this->isStructType() && (this->toStructType()->isTypePacked); } bool Type::isArrayType() { return this->kind == TypeKind::Array; } bool Type::isFloatingPointType() { return this->kind == TypeKind::Primitive && (this->toPrimitiveType()->primKind == PrimitiveType::Kind::Floating); } bool Type::isIntegerType() { return this->kind == TypeKind::Primitive && (this->toPrimitiveType()->primKind == PrimitiveType::Kind::Integer); } bool Type::isSignedIntType() { return this->isIntegerType() && this->toPrimitiveType()->isSigned(); } bool Type::isUnsignedIntType() { return this->isIntegerType() && !this->toPrimitiveType()->isSigned(); } bool Type::isFunctionType() { return this->kind == TypeKind::Function; } bool Type::isPrimitiveType() { return this->kind == TypeKind::Primitive; } bool Type::isPointerType() { return this->kind == TypeKind::Pointer; } bool Type::isVoidType() { return this->kind == TypeKind::Void; } bool Type::isDynamicArrayType() { return this->kind == TypeKind::DynamicArray; } bool Type::isVariadicArrayType() { return this->isArraySliceType() && this->toArraySliceType()->isVariadicType(); } bool Type::isArraySliceType() { return this->kind == TypeKind::ArraySlice; } bool Type::isRangeType() { return this->kind == TypeKind::Range; } bool Type::isStringType() { return this->kind == TypeKind::String; } bool Type::isCharType() { return this == fir::Type::getInt8(); } bool Type::isEnumType() { return this->kind == TypeKind::Enum; } bool Type::isUnionType() { return this->kind == TypeKind::Union; } bool Type::isRawUnionType() { return this->kind == TypeKind::RawUnion; } bool Type::isAnyType() { return this->kind == TypeKind::Any; } bool Type::isNullType() { return this->kind == TypeKind::Null; } bool Type::isBoolType() { return this == fir::Type::getBool(); } bool Type::isMutablePointer() { return this->isPointerType() && this->toPointerType()->isMutable(); } bool Type::isImmutablePointer() { return this->isPointerType() && !this->toPointerType()->isMutable(); } bool Type::isCharSliceType() { return this->isArraySliceType() && this->getArrayElementType() == fir::Type::getInt8(); } bool Type::isPolyPlaceholderType() { return this->kind == TypeKind::PolyPlaceholder; } bool Type::isUnionVariantType() { return this->kind == TypeKind::UnionVariant; } bool Type::isOpaqueType() { return this->kind == TypeKind::Opaque; } bool Type::isTraitType() { return this->kind == TypeKind::Trait; } // static getting functions VoidType* Type::getVoid() { return VoidType::get(); } NullType* Type::getNull() { return NullType::get(); } Type* Type::getVoidPtr() { return VoidType::get()->getPointerTo(); } BoolType* Type::getBool() { return BoolType::get(); } PrimitiveType* Type::getInt8() { return PrimitiveType::getInt8(); } PrimitiveType* Type::getInt16() { return PrimitiveType::getInt16(); } PrimitiveType* Type::getInt32() { return PrimitiveType::getInt32(); } PrimitiveType* Type::getInt64() { return PrimitiveType::getInt64(); } PrimitiveType* Type::getInt128() { return PrimitiveType::getInt128(); } PrimitiveType* Type::getUint8() { return PrimitiveType::getUint8(); } PrimitiveType* Type::getUint16() { return PrimitiveType::getUint16(); } PrimitiveType* Type::getUint32() { return PrimitiveType::getUint32(); } PrimitiveType* Type::getUint64() { return PrimitiveType::getUint64(); } PrimitiveType* Type::getUint128() { return PrimitiveType::getUint128(); } PrimitiveType* Type::getFloat32() { return PrimitiveType::getFloat32(); } PrimitiveType* Type::getFloat64() { return PrimitiveType::getFloat64(); } PrimitiveType* Type::getFloat128() { return PrimitiveType::getFloat128(); } PointerType* Type::getInt8Ptr() { return PointerType::getInt8Ptr(); } PointerType* Type::getInt16Ptr() { return PointerType::getInt16Ptr(); } PointerType* Type::getInt32Ptr() { return PointerType::getInt32Ptr(); } PointerType* Type::getInt64Ptr() { return PointerType::getInt64Ptr(); } PointerType* Type::getInt128Ptr() { return PointerType::getInt128Ptr(); } PointerType* Type::getUint8Ptr() { return PointerType::getUint8Ptr(); } PointerType* Type::getUint16Ptr() { return PointerType::getUint16Ptr(); } PointerType* Type::getUint32Ptr() { return PointerType::getUint32Ptr(); } PointerType* Type::getUint64Ptr() { return PointerType::getUint64Ptr(); } PointerType* Type::getUint128Ptr() { return PointerType::getUint128Ptr(); } PointerType* Type::getMutInt8Ptr() { return PointerType::getInt8Ptr()->getMutable(); } PointerType* Type::getMutInt16Ptr() { return PointerType::getInt16Ptr()->getMutable(); } PointerType* Type::getMutInt32Ptr() { return PointerType::getInt32Ptr()->getMutable(); } PointerType* Type::getMutInt64Ptr() { return PointerType::getInt64Ptr()->getMutable(); } PointerType* Type::getMutInt128Ptr() { return PointerType::getInt128Ptr()->getMutable(); } PointerType* Type::getMutUint8Ptr() { return PointerType::getUint8Ptr()->getMutable(); } PointerType* Type::getMutUint16Ptr() { return PointerType::getUint16Ptr()->getMutable(); } PointerType* Type::getMutUint32Ptr() { return PointerType::getUint32Ptr()->getMutable(); } PointerType* Type::getMutUint64Ptr() { return PointerType::getUint64Ptr()->getMutable(); } PointerType* Type::getMutUint128Ptr() { return PointerType::getUint128Ptr()->getMutable(); } ArraySliceType* Type::getCharSlice(bool mut) { return ArraySliceType::get(fir::Type::getInt8(), mut); } RangeType* Type::getRange() { return RangeType::get(); } StringType* Type::getString() { return StringType::get(); } AnyType* Type::getAny() { return AnyType::get(); } static size_t getAggregateSize(const std::vector& tys, bool packed = false) { size_t ptr = 0; size_t aln = 0; if(packed) { // gg // return util::foldl(0, tys, [](Type* a, Type* b) -> size_t { // return getSizeOfType(a) + getSizeOfType(b); // }); size_t ret = 0; for(const auto& t : tys) ret += getSizeOfType(t); return ret; } else { for(auto ty : tys) { auto a = getAlignmentOfType(ty); iceAssert(a > 0); if(ptr % a > 0) ptr += (a - (ptr % a)); ptr += getSizeOfType(ty); aln = std::max(aln, a); } iceAssert(aln > 0); if(ptr % aln > 0) ptr += (aln - (ptr % aln)); return ptr; } } size_t getSizeOfType(Type* type) { auto ptrt = fir::Type::getInt8Ptr(); auto wordty = fir::Type::getNativeWord(); if(type->isVoidType()) return 0; else if(type->isBoolType()) return 1; else if(type->isPrimitiveType()) return type->getBitWidth() / 8; else if(type->isArraySliceType()) return getAggregateSize({ ptrt, wordty }); else if(type->isStringType() || type->isDynamicArrayType()) return getAggregateSize({ ptrt, wordty, wordty, ptrt }); else if(type->isRangeType()) return getAggregateSize({ wordty, wordty, wordty }); else if(type->isPointerType() || type->isFunctionType() || type->isNullType()) { return getSizeOfType(wordty); } else if(type->isArrayType()) { return type->toArrayType()->getArraySize() * getSizeOfType(type->getArrayElementType()); } else if(type->isEnumType()) { return getAggregateSize({ wordty, type->toEnumType()->getCaseType() }); } else if(type->isAnyType()) { return getAggregateSize({ wordty, ptrt, fir::ArrayType::get(fir::Type::getInt8(), BUILTIN_ANY_DATA_BYTECOUNT) }); } else if(type->isClassType() || type->isStructType() || type->isTupleType()) { bool packed = false; std::vector tys; if(type->isClassType()) { tys = type->toClassType()->getAllElementsIncludingBase(); tys.insert(tys.begin(), fir::Type::getInt8Ptr()); } else if(type->isStructType()) { packed = type->toStructType()->isPackedStruct(); tys = type->toStructType()->getElements(); } else { tys = type->toTupleType()->getElements(); } return getAggregateSize(tys, packed); } else if(type->isUnionType() ) { auto ut = type->toUnionType(); size_t maxSz = 0; for(auto v : ut->getVariants()) { if(!v.second->getInteriorType()->isVoidType()) maxSz = std::max(maxSz, getSizeOfType(v.second->getInteriorType())); } if(maxSz > 0) { return getAggregateSize({ wordty, ArrayType::get(Type::getInt8(), maxSz) }); } else { return getAggregateSize({ wordty }); } } else if(type->isRawUnionType()) { auto ut = type->toRawUnionType(); size_t maxSz = 0; for(const auto& v : ut->getVariants()) maxSz = std::max(maxSz, getSizeOfType(v.second)); iceAssert(maxSz > 0); return getAggregateSize({ ArrayType::get(Type::getInt8(), maxSz) }); } else if(type->isUnionVariantType()) { return getSizeOfType(type->toUnionVariantType()->getInteriorType()); } else if(type->isOpaqueType()) { return type->toOpaqueType()->getTypeSizeInBits() / 8; } else { error("cannot get size of unsupported type '%s'", type); } } size_t getAlignmentOfType(Type* type) { if(type->isArrayType()) return getAlignmentOfType(type->getArrayElementType()); else return getSizeOfType(type); } bool isRefCountedType(Type* type) { // strings, and structs with rc inside if(type->isStructType()) { for(auto m : type->toStructType()->getElements()) { if(isRefCountedType(m)) return true; } return false; } else if(type->isClassType()) { for(auto m : type->toClassType()->getElements()) { if(isRefCountedType(m)) return true; } return false; } else if(type->isTupleType()) { for(auto m : type->toTupleType()->getElements()) { if(isRefCountedType(m)) return true; } return false; } else if(type->isArrayType()) // note: no slices, because slices don't own memory { return isRefCountedType(type->getArrayElementType()); } else { return type->isStringType() || type->isAnyType() || type->isDynamicArrayType(); } } } ================================================ FILE: source/fir/Types/TypeUtils.cpp ================================================ // TypeUtils.cpp // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. #include "errors.h" #include "ir/type.h" #include "ir/function.h" namespace fir { static bool _checkTypeVariance(Type* base, Type* derv, bool contra, bool trait) { if(base == derv) return true; // for now, we only support inheritance and stuff on pointers. if(!base->isPointerType() || !derv->isPointerType()) return false; auto baseelm = base->getPointerElementType(); auto dervelm = derv->getPointerElementType(); if(baseelm->isClassType() && dervelm->isClassType()) { // if contravariant, then derv must be more general than base. if(contra) return baseelm->toClassType()->hasParent(dervelm); else return dervelm->toClassType()->hasParent(baseelm); } else { // if contra, check if base implements derv as a trait // else check if derv implements base as a trait. of course, if the thing that // is supposed to be a trait isn't a trait, it doesn't work. if(contra) { // if contra *BUT* we are checking traits, then we should allow the case where the // derived type is covariant (ie. implements the trait!) if(trait) { // TODO: this might not be correct? std::swap(baseelm, dervelm); } if(!dervelm->isTraitType()) return false; return (baseelm->isStructType() && baseelm->toStructType()->implementsTrait(dervelm->toTraitType())) || (dervelm->isStructType() && dervelm->toStructType()->implementsTrait(baseelm->toTraitType())); } else { if(!baseelm->isTraitType()) return false; return (dervelm->isStructType() && dervelm->toStructType()->implementsTrait(baseelm->toTraitType())) || (baseelm->isStructType() && baseelm->toStructType()->implementsTrait(dervelm->toTraitType())); } } } bool areTypesCovariant(Type* base, Type* derv) { return _checkTypeVariance(base, derv, false, false); } bool areTypesContravariant(Type* base, Type* derv, bool traitChecking) { return _checkTypeVariance(base, derv, true, traitChecking); } bool areTypeListsContravariant(const std::vector& base, const std::vector& derv, bool traitChecking) { // parameters must be contravariant, ie. fn must take more general types than base // return type must be covariant, ie. fn must return a more specific type than base. // duh if(base.size() != derv.size()) return false; // drop the first argument. for(auto [ b, d ] : zfu::zip(base, derv)) { if(!areTypesContravariant(b, d, traitChecking)) return false; } return true; } bool areMethodsVirtuallyCompatible(FunctionType* base, FunctionType* fn, bool traitChecking) { bool ret = areTypeListsContravariant(zfu::drop(base->getArgumentTypes(), 1), zfu::drop(fn->getArgumentTypes(), 1), traitChecking); if(!ret) return false; auto baseRet = base->getReturnType(); auto fnRet = fn->getReturnType(); // ok now check the return type. return areTypesCovariant(baseRet, fnRet); } } ================================================ FILE: source/fir/Types/UnionType.cpp ================================================ // UnionType.cpp // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #include "errors.h" #include "ir/type.h" #include "pts.h" namespace fir { // structs UnionType::UnionType(const Name& name, const util::hash_map>& mems) : Type(TypeKind::Union), unionName(name) { this->setBody(mems); } static util::hash_map typeCache; UnionType* UnionType::create(const Name& name, const util::hash_map>& mems) { if(auto it = typeCache.find(name); it != typeCache.end()) error("union with name '%s' already exists", name.str()); else return (typeCache[name] = new UnionType(name, mems)); } UnionType* UnionType::createWithoutBody(const Name& name) { return UnionType::create(name, { }); } // various std::string UnionType::str() { return "union(" + this->unionName.name + ")"; } std::string UnionType::encodedStr() { return this->unionName.str(); } bool UnionType::isTypeEqual(Type* other) { if(other->kind != TypeKind::Union) return false; return (this->unionName == other->toUnionType()->unionName); } // struct stuff Name UnionType::getTypeName() { return this->unionName; } size_t UnionType::getVariantCount() { return this->variants.size(); } size_t UnionType::getIdOfVariant(const std::string& name) { if(auto it = this->variants.find(name); it != this->variants.end()) return it->second->variantId; else error("no variant with name '%s'", name); } const util::hash_map& UnionType::getVariants() { return this->variants; } bool UnionType::hasVariant(const std::string& name) { return this->variants.find(name) != this->variants.end(); } UnionVariantType* UnionType::getVariant(size_t id) { if(auto it = this->indexMap.find(id); it != this->indexMap.end()) return it->second; else error("no variant with id %d", id); } UnionVariantType* UnionType::getVariant(const std::string& name) { if(auto it = this->variants.find(name); it != this->variants.end()) return it->second; else error("no variant named '%s' in union '%s'", name, this->getTypeName().str()); } void UnionType::setBody(const util::hash_map>& members) { for(const auto& [ n, p ] : members) { auto uvt = new UnionVariantType(this, p.first, n, p.second); this->variants[n] = uvt; this->indexMap[p.first] = uvt; } } fir::Type* UnionType::substitutePlaceholders(const util::hash_map& subst) { if(this->containsPlaceholders()) error("not supported!"); return this; } std::string UnionVariantType::str() { return this->parent->str() + "::" + this->name; } std::string UnionVariantType::encodedStr() { return this->parent->encodedStr() + "::" + this->name; } bool UnionVariantType::isTypeEqual(Type* other) { if(auto uvt = dcast(UnionVariantType, other)) return uvt->parent == this->parent && uvt->name == this->name; return false; } fir::Type* UnionVariantType::substitutePlaceholders(const util::hash_map& subst) { if(this->containsPlaceholders()) error("not supported!"); return this; } UnionVariantType::UnionVariantType(UnionType* p, size_t id, const std::string& name, Type* actual) : Type(TypeKind::UnionVariant) { this->parent = p; this->name = name; this->variantId = id; this->interiorType = actual; } } ================================================ FILE: source/fir/Value.cpp ================================================ // Value.cpp // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #include "ir/value.h" #include "ir/constant.h" namespace fir { static size_t vnames = 0; Value::Value(Type* t, Kind k) : ident(Name::of("")), valueType(t), kind(k) { this->id = vnames++; } Type* Value::getType() { if(this->valueType) return this->valueType; error("value has no type????"); } bool Value::hasName() { return this->ident.str() != ""; } void Value::setName(const Name& name) { this->ident = name; } void Value::setName(const std::string& name) { this->ident = Name::of(name); } const Name& Value::getName() { return this->ident; } size_t Value::getCurrentValueId() { return vnames; } void PHINode::addIncoming(Value* v, IRBlock* block) { iceAssert(v->getType() == this->valueType && "types not identical"); if(this->incoming.find(block) != this->incoming.end()) iceAssert(0 && "block already has incoming value"); this->incoming[block] = v; } std::map PHINode::getValues() { return this->incoming; } PHINode::PHINode(Type* t) : fir::Value(t) { } } ================================================ FILE: source/fir/interp/compiler.cpp ================================================ // compiler.cpp // Copyright (c) 2017, zhiayang@gmail.com // Licensed under the Apache License Version 2.0. #include "ir/type.h" #include "ir/value.h" #include "ir/interp.h" #include "ir/module.h" #include "ir/function.h" #include "ir/instruction.h" namespace fir { namespace interp { static interp::Instruction compileInstruction(InterpState* is, fir::Function* parent, fir::Instruction* finstr) { iceAssert(finstr); interp::Instruction ret; ret.result = finstr->realOutput; ret.opcode = static_cast(finstr->opKind); for(auto a : finstr->operands) ret.args.push_back(a); return ret; } static interp::Block compileBlock(InterpState* is, fir::Function* parent, fir::IRBlock* fib) { iceAssert(fib); interp::Block ret; ret.blk = fib; ret.instructions = zfu::map(fib->getInstructions(), [is, parent](fir::Instruction* i) -> interp::Instruction { return compileInstruction(is, parent, i); }); return ret; } interp::Function& InterpState::compileFunction(fir::Function* fn) { iceAssert(fn); interp::Function ret; ret.func = fn; ret.blocks = zfu::map(fn->getBlockList(), [fn, this](fir::IRBlock* b) -> interp::Block { return compileBlock(this, fn, b); }); if(fn->isCStyleVarArg()) iceAssert(ret.blocks.empty()); if(ret.blocks.empty()) ret.isExternal = true, ret.extFuncName = fn->getName().name; // add it. this->compiledFunctions[ret.func] = ret; return this->compiledFunctions[ret.func]; } } } ================================================ FILE: source/fir/interp/interpreter.cpp ================================================ // interpreter.cpp // Copyright (c) 2017, zhiayang@gmail.com // Licensed under the Apache License Version 2.0. #include "ir/type.h" #include "ir/value.h" #include "ir/interp.h" #include "ir/module.h" #include "ir/function.h" #include "ir/instruction.h" #include "frontend.h" #include "gluecode.h" #include "platform.h" #define FFI_BUILDING #include #define LARGE_DATA_SIZE 32 #define SLICE_DATA_INDEX 0 #define SLICE_LENGTH_INDEX 1 #define SAA_DATA_INDEX 0 #define SAA_LENGTH_INDEX 1 #define SAA_CAPACITY_INDEX 2 #define SAA_REFCOUNTPTR_INDEX 3 #define ANY_TYPEID_INDEX 0 #define ANY_REFCOUNTPTR_INDEX 1 #define ANY_DATA_ARRAY_INDEX 2 #ifdef _MSC_VER #pragma warning(push, 0) #pragma warning(disable: 4018) #else /* so msvc doesn't really warn on this. we disable these warnings locally, because of the way we're doing the operations. we can guarantee (because IRBuilder says so) that we won't be doing strange things like bitwise-not-ing a boolean or left-shifting a floating point, but the compiler won't know so we just ignore these things to clean up the output. */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpragmas" #pragma GCC diagnostic ignored "-Wunknown-warning-option" #pragma GCC diagnostic ignored "-Wbool-operation" #pragma GCC diagnostic ignored "-Wint-in-bool-context" #pragma GCC diagnostic ignored "-Wimplicit-conversion-floating-point-to-bool" #pragma GCC diagnostic ignored "-Wdelete-incomplete" #endif namespace fir { namespace interp { //! ACHTUNG ! //* in the interpreter, we assume all structs are packed, and there are no padding/alignment bytes anywhere. //* this greatly simplifies everything, and the performance impact is probably insignificant next to the (power of the force) //* whole interpreter anyway. template static interp::Value makeValue(fir::Value* fv, const T& val) { interp::Value ret; ret.val = fv; ret.type = fv->getType(); ret.dataSize = sizeof(T); if(auto fsz = getSizeOfType(ret.type); fsz != sizeof(T)) error("packing error of type '%s': predicted size %d, actual size %d!", ret.type, fsz, sizeof(T)); memset(&ret.data[0], 0, LARGE_DATA_SIZE); if(sizeof(T) > LARGE_DATA_SIZE) { ret.ptr = malloc(sizeof(T)); memmove(ret.ptr, &val, sizeof(T)); } else { memmove(&ret.data[0], &val, sizeof(T)); } return ret; } // this lets us specify the type, instead of using the one in the Value static interp::Value makeValueOfType(fir::Value* fv, fir::Type* ty) { interp::Value ret; ret.val = fv; ret.type = ty; ret.dataSize = getSizeOfType(ret.type); memset(&ret.data[0], 0, LARGE_DATA_SIZE); if(ret.dataSize > LARGE_DATA_SIZE) ret.ptr = calloc(1, ret.dataSize); return ret; } interp::Value InterpState::makeValue(fir::Value* fv) { return makeValueOfType(fv, fv->getType()); } template static T getActualValue(const interp::Value& v) { if(v.dataSize > LARGE_DATA_SIZE) { return *(static_cast(v.ptr)); } else { return *(reinterpret_cast(const_cast(&v.data[0]))); } } static interp::Value cloneValue(const interp::Value& v) { interp::Value ret = v; if(v.dataSize > LARGE_DATA_SIZE) { ret.ptr = calloc(1, v.dataSize); memmove(ret.ptr, v.ptr, v.dataSize); } return ret; } static interp::Value cloneValue(fir::Value* fv, const interp::Value& v) { interp::Value ret = v; ret.val = fv; ret.globalValTracker = v.globalValTracker; if(v.dataSize > LARGE_DATA_SIZE) { ret.ptr = calloc(1, v.dataSize); memmove(ret.ptr, v.ptr, v.dataSize); } return ret; } static void setValueRaw(InterpState* is, interp::Value* target, void* value, size_t sz) { if(target->dataSize != sz) error("interp: cannot set value, size mismatch (%d vs %d)", target->dataSize, sz); if(sz > LARGE_DATA_SIZE) { if(!target->ptr) target->ptr = calloc(1, sz); memmove(target->ptr, value, sz); } else { memmove(&target->data[0], value, sz); } } static void setValue(InterpState* is, interp::Value* target, const interp::Value& val) { if(target->type != val.type) error("interp: cannot set value, conflicting types '%s' and '%s'", target->type, val.type); if(val.dataSize > LARGE_DATA_SIZE) memmove(target->ptr, val.ptr, val.dataSize); else memmove(&target->data[0], &val.data[0], val.dataSize); } static char* makeGlobalString(InterpState* is, const std::string& str) { auto s = new char[str.size() + 1]; memmove(s, str.c_str(), str.size()); s[str.size()] = 0; is->strings.push_back(s); return s; } static interp::Value loadFromPtr(const interp::Value& x, fir::Type* ty) { auto ptr = reinterpret_cast(getActualValue(x)); interp::Value ret; ret.dataSize = getSizeOfType(ty); ret.type = ty; if(ret.dataSize > LARGE_DATA_SIZE) { // clone the memory and store it. auto newmem = malloc(ret.dataSize); memmove(newmem, ptr, ret.dataSize); ret.ptr = newmem; } else { // memcopy. memmove(&ret.data[0], ptr, ret.dataSize); } return ret; } static std::map cachedConstants; static interp::Value makeConstant(InterpState* is, ConstantValue* c) { auto constructStructThingy2 = [](fir::Value* val, size_t datasize, const std::vector& inserts) -> interp::Value { uint8_t* buffer = 0; interp::Value ret; ret.dataSize = datasize; ret.type = val->getType(); ret.val = val; if(datasize > LARGE_DATA_SIZE) { buffer = new uint8_t[datasize]; ret.ptr = buffer; } else { buffer = &ret.data[0]; } iceAssert(buffer); uint8_t* ofs = buffer; for(const auto& v : inserts) { if(v.dataSize > LARGE_DATA_SIZE) memmove(ofs, v.ptr, v.dataSize); else memmove(ofs, &v.data[0], v.dataSize); ofs += v.dataSize; } return ret; }; auto constructStructThingy = [is, &constructStructThingy2](fir::Value* val, size_t datasize, const std::vector& inserts) -> interp::Value { std::vector vals; vals.reserve(inserts.size()); for(const auto& x : inserts) vals.push_back(makeConstant(is, x)); return constructStructThingy2(val, datasize, vals); }; if(auto ci = dcast(fir::ConstantInt, c)) { interp::Value ret; if(ci->getType() == fir::Type::getInt8()) ret = makeValue(c, static_cast(ci->getSignedValue())); else if(ci->getType() == fir::Type::getInt16()) ret = makeValue(c, static_cast(ci->getSignedValue())); else if(ci->getType() == fir::Type::getInt32()) ret = makeValue(c, static_cast(ci->getSignedValue())); else if(ci->getType() == fir::Type::getInt64()) ret = makeValue(c, static_cast(ci->getSignedValue())); else if(ci->getType() == fir::Type::getUint8()) ret = makeValue(c, static_cast(ci->getUnsignedValue())); else if(ci->getType() == fir::Type::getUint16()) ret = makeValue(c, static_cast(ci->getUnsignedValue())); else if(ci->getType() == fir::Type::getUint32()) ret = makeValue(c, static_cast(ci->getUnsignedValue())); else if(ci->getType() == fir::Type::getUint64()) ret = makeValue(c, static_cast(ci->getUnsignedValue())); else error("interp: unsupported type '%s' for integer constant", ci->getType()); return (cachedConstants[c] = ret); } else if(auto cf = dcast(fir::ConstantFP, c)) { return cachedConstants[c] = makeValue(c, cf->getValue()); } else if(auto cb = dcast(fir::ConstantBool, c)) { return cachedConstants[c] = makeValue(c, cb->getValue()); } else if(auto cs = dcast(fir::ConstantCharSlice, c)) { auto str = makeGlobalString(is, cs->getValue()); auto ptr = fir::ConstantBitcast::get(fir::ConstantInt::getUNative(reinterpret_cast(str)), fir::Type::getInt8Ptr()); auto len = fir::ConstantInt::getNative(cs->getValue().size()); auto bytecount = getSizeOfType(cs->getType()); auto ret = constructStructThingy(cs, bytecount, { ptr, len }); return (cachedConstants[c] = ret); } else if(auto cbc = dcast(fir::ConstantBitcast, c)) { auto thing = makeConstant(is, cbc->getValue()); auto ret = cloneValue(cbc, thing); return (cachedConstants[c] = ret); } else if(auto ca = dcast(fir::ConstantArray, c)) { auto bytecount = getSizeOfType(ca->getType()); auto ret = constructStructThingy(ca, bytecount, ca->getValues()); return (cachedConstants[c] = ret); } else if(auto ct = dcast(fir::ConstantTuple, c)) { size_t bytecount = getSizeOfType(ct->getType()); auto ret = constructStructThingy(ct, bytecount, ct->getValues()); return (cachedConstants[c] = ret); } else if(auto cec = dcast(fir::ConstantEnumCase, c)) { auto bytecount = getSizeOfType(cec->getType()); auto ret = constructStructThingy(cec, bytecount, { cec->getIndex(), cec->getValue() }); return (cachedConstants[c] = ret); } else if(auto cas = dcast(fir::ConstantArraySlice, c)) { auto ptr = cas->getData(); auto len = cas->getLength(); auto bytecount = getSizeOfType(cas->getType()); auto ret = constructStructThingy(cas, bytecount, { ptr, len }); return (cachedConstants[c] = ret); } else if(auto cds = dcast(fir::ConstantDynamicString, c)) { auto str = makeGlobalString(is, cds->getValue()); auto ptr = fir::ConstantBitcast::get(fir::ConstantInt::getUNative(reinterpret_cast(str)), fir::Type::getInt8Ptr()); auto len = fir::ConstantInt::getNative(cds->getValue().size()); auto bytecount = getSizeOfType(cds->getType()); // add -1 for capacity and 0 for refcountptr. auto ret = constructStructThingy(cds, bytecount, { ptr, len, fir::ConstantInt::getNative(-1), fir::ConstantInt::getNative(0) }); return (cachedConstants[c] = ret); } else if(auto cda = dcast(fir::ConstantDynamicArray, c)) { std::vector mems; auto bytecount = getSizeOfType(cda->getType()); if(cda->getArray()) { auto theArray = cda->getArray(); auto sz = getSizeOfType(theArray->getType()); void* buffer = new uint8_t[sz]; memset(buffer, 0, sz); is->globalAllocs.push_back(buffer); uint8_t* ofs = reinterpret_cast(buffer); for(auto x : theArray->getValues()) { auto v = makeConstant(is, x); if(v.dataSize > LARGE_DATA_SIZE) memmove(ofs, v.ptr, v.dataSize); else memmove(ofs, &v.data[0], v.dataSize); ofs += v.dataSize; } interp::Value fakeptr; fakeptr.val = 0; fakeptr.type = cda->getType()->getArrayElementType()->getMutablePointerTo(); fakeptr.dataSize = sizeof(void*); setValueRaw(is, &fakeptr, &buffer, sizeof(void*)); mems = { fakeptr, makeConstant(is, fir::ConstantInt::getNative(theArray->getValues().size())), makeConstant(is, fir::ConstantInt::getNative(-1)), makeConstant(is, fir::ConstantInt::getNative(0)) }; } else { mems = { makeConstant(is, cda->getData()), makeConstant(is, cda->getLength()), makeConstant(is, cda->getCapacity()), makeConstant(is, fir::ConstantInt::getNative(0)) }; } auto ret = constructStructThingy2(cda, bytecount, mems); return (cachedConstants[c] = ret); } else if(auto fn = dcast(fir::Function, c)) { // ok -- when we get a "function" as a constant, what really happened in the source code is that we referred to a function // by name, without calling it. we expect, then, to get a function pointer out of it. // the problem is, we can also call function pointers that come from raw pointers that point to *real* CPU instructions // somewhere --- nobody is stopping the program from calling dlsym() or whatever and calling a function using // that pointer. // so, in order to support that, we return the fir::Function itself as a pointer. when we do the pointer-call, the // stub function will check the list of functions to see if it was a source-originated function, and if so call it // normally. if not, then we will use libffi to call it. // make sure we compile it first, so it gets added to InterpState::compiledFunctions is->compileFunction(fn); auto ret = makeValue(fn, reinterpret_cast(fn)); return (cachedConstants[c] = ret); } else if(auto glob = dcast(fir::GlobalValue, c)) { if(auto it = is->globals.find(c); it != is->globals.end()) return it->second.first; else error("interp: global value '%s' id %d was not found", glob->getName().str(), glob->id); } else { iceAssert(c); auto ret = is->makeValue(c); return (cachedConstants[c] = ret); } } InterpState::InterpState(Module* mod) : module(mod) { } InterpState::~InterpState() { } void InterpState::initialise(bool runGlobalInit) { iceAssert(this->module); for(const auto& [ str, glob ] : this->module->_getGlobalStrings()) { auto val = makeValue(glob); auto s = makeGlobalString(this, str); setValueRaw(this, &val, &s, sizeof(char*)); val.globalValTracker = glob; this->globals[glob] = { val, false }; } for(const auto& [ id, glob ] : this->module->_getGlobals()) { auto ty = glob->getType(); auto sz = getSizeOfType(ty); void* buffer = new uint8_t[sz]; memset(buffer, 0, sz); this->globalAllocs.push_back(buffer); if(auto init = glob->getInitialValue(); init) { auto x = makeConstant(this, init); if(x.dataSize > LARGE_DATA_SIZE) memmove(buffer, x.ptr, x.dataSize); else memmove(buffer, &x.data[0], x.dataSize); } auto ret = makeValueOfType(glob, ty->getPointerTo()); setValueRaw(this, &ret, &buffer, sizeof(void*)); ret.globalValTracker = glob; this->globals[glob] = { ret, false }; } for(const auto& [ id, intr ] : this->module->_getIntrinsicFunctions()) { auto fname = Name::of(zpr::sprint("__interp_intrinsic_%s", id.str())); auto fn = this->module->getOrCreateFunction(fname, intr->getType(), fir::LinkageType::ExternalWeak); // interp::compileFunction already maps the newly compiled interp::Function, but since we created a // new function here `fn` that doesn't match the intrinsic function `intr`, we need to map that as well. this->compiledFunctions[intr] = this->compileFunction(fn); } #if OS_WINDOWS // ok, this is mostly for windows --- printf and friends are not *real* functions, but rather // macros defined in stdio.h, or something like that. so, we make "intrinsic wrappers" that call // it in the interpreter, which we dlopen into the context anyway. { std::vector names = { "printf", "sprintf", "snprintf", "fprintf" }; for(const auto& name : names) { auto fn = this->module->getFunction(Name::of(name)); if(fn) { auto wrapper = this->module->getOrCreateFunction(Name::of(zpr::sprint("__interp_wrapper_%s", name)), fn->getType()->toFunctionType(), fir::LinkageType::ExternalWeak); this->compiledFunctions[fn] = this->compileFunction(wrapper); } } } #endif // printf("module:\n%s\n", this->module->print().c_str()); // truth be told it'll be more efficient to only get the function after checking runGlobalInit, but... meh. if(auto gif = this->module->getFunction(Name::obfuscate(strs::names::GLOBAL_INIT_FUNCTION)); runGlobalInit && gif) { auto cgif = this->compileFunction(gif); this->runFunction(cgif, { }); } } // the purpose of this function is to write-back any changes we made to globals while interpreting, // back to the "value" of the global -- mainly for compile-time execution, so modifications will // propagate to the backend code generation. void InterpState::finalise() { for(const auto& [ id, glob ] : this->module->_getGlobals()) { // printf("global: %s\n", id.str().c_str()); // by right we are not supposed to add (or even change the FIR module at all) between calling // initialise() and finalise(), but be defensive a bit. if(auto it = this->globals.find(glob); it != this->globals.end()) { // printf("found: %s\n", id.str().c_str()); // only write-back if we modified the global. if(it->second.second) { auto val = loadFromPtr(it->second.first, it->first->getType()); auto x = this->unwrapInterpValueIntoConstant(val); // printf("write-back: %s = %s\n", id.name.c_str(), x->str().c_str()); glob->setInitialValue(x); it->second.second = false; } } } for(void* p : this->globalAllocs) delete[] p; this->globalAllocs.clear(); } static ffi_type* convertTypeToLibFFI(fir::Type* ty) { if(ty->isPointerType()) { return &ffi_type_pointer; } else if(ty->isBoolType()) { //? HMMM.... return &ffi_type_uint8; } else if(ty->isVoidType()) { return &ffi_type_void; } else if(ty->isIntegerType()) { if(ty == Type::getInt8()) return &ffi_type_sint8; if(ty == Type::getInt16()) return &ffi_type_sint16; if(ty == Type::getInt32()) return &ffi_type_sint32; if(ty == Type::getInt64()) return &ffi_type_sint64; if(ty == Type::getUint8()) return &ffi_type_uint8; if(ty == Type::getUint16()) return &ffi_type_uint16; if(ty == Type::getUint32()) return &ffi_type_uint32; if(ty == Type::getUint64()) return &ffi_type_uint64; } else if(ty->isFloatingPointType()) { if(ty == Type::getFloat32()) return &ffi_type_float; if(ty == Type::getFloat64()) return &ffi_type_double; } error("interp: unsupported type '%s' in libffi-translation", ty); } static size_t getOffsetOfTypeInTypeList(const std::vector& elms, size_t idx) { size_t ofs = 0; for(uint64_t i = 0; i < idx; i++) { auto aln = getAlignmentOfType(elms[i]); if(ofs % aln > 0) ofs += (aln - (ofs % aln)); ofs += getSizeOfType(elms[i]); } return ofs; } static std::vector getTypeListOfType(fir::Type* ty) { if(ty->isStructType()) { return ty->toStructType()->getElements(); } else if(ty->isClassType()) { auto ret = ty->toClassType()->getAllElementsIncludingBase(); if(ty->toClassType()->getVirtualMethodCount() > 0) ret.insert(ret.begin(), fir::Type::getInt8Ptr()); return ret; } else if(ty->isTupleType()) { return ty->toTupleType()->getElements(); } else if(ty->isArraySliceType()) { if(ty->toArraySliceType()->isMutable()) return { ty->getArrayElementType()->getMutablePointerTo(), fir::Type::getNativeWord() }; else return { ty->getArrayElementType()->getPointerTo(), fir::Type::getNativeWord() }; } else if(ty->isAnyType()) { return { fir::Type::getNativeUWord(), fir::Type::getNativeWordPtr(), fir::ArrayType::get(fir::Type::getInt8(), BUILTIN_ANY_DATA_BYTECOUNT) }; } else if(ty->isRangeType()) { return { fir::Type::getNativeWord(), fir::Type::getNativeWord(), fir::Type::getNativeWord() }; } else if(ty->isEnumType()) { return { fir::Type::getNativeWord(), ty->toEnumType()->getCaseType() }; } else if(ty->isStringType() || ty->isDynamicArrayType()) { std::vector mems(4); if(ty->isDynamicArrayType()) mems[SAA_DATA_INDEX] = ty->getArrayElementType()->getMutablePointerTo(); else mems[SAA_DATA_INDEX] = fir::Type::getMutInt8Ptr(); mems[SAA_LENGTH_INDEX] = fir::Type::getNativeWord(); mems[SAA_CAPACITY_INDEX] = fir::Type::getNativeWord(); mems[SAA_REFCOUNTPTR_INDEX] = fir::Type::getNativeWordPtr(); return mems; } else { error("interp: unsupported type '%s' for insert/extractvalue", ty); } } static interp::Value doInsertValue(interp::InterpState* is, fir::Value* res, const interp::Value& str, const interp::Value& elm, size_t idx) { // we clone the value first auto ret = cloneValue(res, str); size_t ofs = 0; if(str.type->isArrayType()) { auto arrty = str.type->toArrayType(); iceAssert(idx < arrty->getArraySize()); ofs = idx * getSizeOfType(arrty->getElementType()); } else if(str.type->isUnionType()) { // we only support getting the id with insert/extractvalue. iceAssert(idx == 0); ofs = 0; } else { auto typelist = getTypeListOfType(str.type); iceAssert(idx < typelist.size()); ofs = getOffsetOfTypeInTypeList(typelist, idx); } uintptr_t dst = 0; if(str.dataSize > LARGE_DATA_SIZE) dst = reinterpret_cast(ret.ptr); else dst = reinterpret_cast(&ret.data[0]); uintptr_t src = 0; if(elm.dataSize > LARGE_DATA_SIZE) src = reinterpret_cast(elm.ptr); else src = reinterpret_cast(&elm.data[0]); memmove(reinterpret_cast(dst + ofs), reinterpret_cast(src), elm.dataSize); return ret; } static interp::Value doExtractValue(interp::InterpState* is, fir::Value* res, const interp::Value& str, size_t idx) { size_t ofs = 0; fir::Type* elm = 0; if(str.type->isArrayType()) { auto arrty = str.type->toArrayType(); iceAssert(idx < arrty->getArraySize()); ofs = idx * getSizeOfType(arrty->getElementType()); elm = arrty->getElementType(); } else if(str.type->isUnionType()) { // we only support getting the id with insert/extractvalue. iceAssert(idx == 0); elm = fir::Type::getNativeWord(); ofs = 0; } else { auto typelist = getTypeListOfType(str.type); iceAssert(idx < typelist.size()); ofs = getOffsetOfTypeInTypeList(typelist, idx); elm = typelist[idx]; } auto ret = is->makeValue(res); iceAssert(ret.type == elm); uintptr_t src = 0; if(str.dataSize > LARGE_DATA_SIZE) src = reinterpret_cast(str.ptr); else src = reinterpret_cast(&str.data[0]); uintptr_t dst = 0; if(ret.dataSize > LARGE_DATA_SIZE) dst = reinterpret_cast(ret.ptr); else dst = reinterpret_cast(&ret.data[0]); memmove(reinterpret_cast(dst), reinterpret_cast(src + ofs), ret.dataSize); return ret; } // this saves us a lot of copy/paste template static interp::Value oneArgumentOpIntOnly(InterpState* is, fir::Type* resty, const interp::Value& a, Functor op) { auto ty = a.type; interp::Value res; res.dataSize = getSizeOfType(resty); res.type = resty; if(ty == Type::getInt8()) { auto tmp = op(getActualValue(a)); setValueRaw(is, &res, &tmp, sizeof(tmp)); return res; } if(ty == Type::getInt16()) { auto tmp = op(getActualValue(a)); setValueRaw(is, &res, &tmp, sizeof(tmp)); return res; } if(ty == Type::getInt32()) { auto tmp = op(getActualValue(a)); setValueRaw(is, &res, &tmp, sizeof(tmp)); return res; } if(ty == Type::getInt64()) { auto tmp = op(getActualValue(a)); setValueRaw(is, &res, &tmp, sizeof(tmp)); return res; } if(ty == Type::getUint8()) { auto tmp = op(getActualValue(a)); setValueRaw(is, &res, &tmp, sizeof(tmp)); return res; } if(ty == Type::getUint16()) { auto tmp = op(getActualValue(a)); setValueRaw(is, &res, &tmp, sizeof(tmp)); return res; } if(ty == Type::getUint32()) { auto tmp = op(getActualValue(a)); setValueRaw(is, &res, &tmp, sizeof(tmp)); return res; } if(ty == Type::getUint64()) { auto tmp = op(getActualValue(a)); setValueRaw(is, &res, &tmp, sizeof(tmp)); return res; } if(ty->isPointerType()) { auto tmp = op(getActualValue(a)); setValueRaw(is, &res, &tmp, sizeof(tmp)); return res; } if(ty->isBoolType()) { auto tmp = op(getActualValue(a)); setValueRaw(is, &res, &tmp, sizeof(tmp)); return res; } else error("interp: unsupported type '%s'", ty); } template static interp::Value oneArgumentOpIntOnly(InterpState* is, const interp::Instruction& inst, const interp::Value& a, Functor op) { auto ret = oneArgumentOpIntOnly(is, inst.result->getType(), a, op); ret.val = inst.result; return ret; } template static interp::Value oneArgumentOp(InterpState* is, fir::Type* resty, const interp::Value& a, Functor op) { auto ty = a.type; if(!ty->isFloatingPointType()) return oneArgumentOpIntOnly(is, resty, a, op); interp::Value res; res.dataSize = getSizeOfType(resty); res.type = resty; if(ty == Type::getFloat32()) { auto tmp = op(getActualValue(a)); setValueRaw(is, &res, &tmp, sizeof(tmp)); return res; } if(ty == Type::getFloat64()) { auto tmp = op(getActualValue(a)); setValueRaw(is, &res, &tmp, sizeof(tmp)); return res; } else error("interp: unsupported type '%s'", ty); } template static interp::Value oneArgumentOp(InterpState* is, const interp::Instruction& inst, const interp::Value& a, Functor op) { auto ret = oneArgumentOp(is, inst.result->getType(), a, op); ret.val = inst.result; return ret; } template static interp::Value twoArgumentOpIntOnly(InterpState* is, fir::Type* resty, const interp::Value& a, const interp::Value& b, Functor op) { auto aty = a.type; auto bty = b.type; using i8tT = int8_t; auto i8t = Type::getInt8(); using i16tT = int16_t; auto i16t = Type::getInt16(); using i32tT = int32_t; auto i32t = Type::getInt32(); using i64tT = int64_t; auto i64t = Type::getInt64(); using u8tT = uint8_t; auto u8t = Type::getUint8(); using u16tT = uint16_t; auto u16t = Type::getUint16(); using u32tT = uint32_t; auto u32t = Type::getUint32(); using u64tT = uint64_t; auto u64t = Type::getUint64(); #define gav(t, x) getActualValue(x) interp::Value res; res.dataSize = getSizeOfType(resty); res.type = resty; #define If(at, bt) do { if(aty == (at) && bty == (bt)) { \ auto tmp = op(gav(at##T, a), gav(bt##T, b)); \ setValueRaw(is, &res, &tmp, sizeof(tmp)); \ return res; \ } } while(0) // FUCK LAH If(i8t, i8t); If(i8t, i16t); If(i8t, i32t); If(i8t, i64t); If(i16t, i8t); If(i16t, i16t); If(i16t, i32t); If(i16t, i64t); If(i32t, i8t); If(i32t, i16t); If(i32t, i32t); If(i32t, i64t); If(i64t, i8t); If(i64t, i16t); If(i64t, i32t); If(i64t, i64t); If(u8t, u8t); If(u8t, u16t); If(u8t, u32t); If(u8t, u64t); If(u16t, u8t); If(u16t, u16t); If(u16t, u32t); If(u16t, u64t); If(u32t, u8t); If(u32t, u16t); If(u32t, u32t); If(u32t, u64t); If(u64t, u8t); If(u64t, u16t); If(u64t, u32t); If(u64t, u64t); if(aty->isPointerType() && bty->isPointerType()) { auto tmp = op(gav(uintptr_t, a), gav(uintptr_t, b)); setValueRaw(is, &res, &tmp, sizeof(tmp)); return res; } if(aty->isBoolType() && bty->isBoolType()) { auto tmp = op(gav(bool, a), gav(bool, b)); setValueRaw(is, &res, &tmp, sizeof(tmp)); return res; } error("interp: unsupported types '%s' and '%s' for arithmetic", aty, bty); #undef If #undef gav } template static interp::Value twoArgumentOp(InterpState* is, fir::Type* resty, const interp::Value& a, const interp::Value& b, Functor op) { if(!(a.type->isFloatingPointType() || b.type->isFloatingPointType())) return twoArgumentOpIntOnly(is, resty, a, b, op); auto aty = a.type; auto bty = b.type; using i8tT = int8_t; auto i8t = Type::getInt8(); using i16tT = int16_t; auto i16t = Type::getInt16(); using i32tT = int32_t; auto i32t = Type::getInt32(); using i64tT = int64_t; auto i64t = Type::getInt64(); using u8tT = uint8_t; auto u8t = Type::getUint8(); using u16tT = uint16_t; auto u16t = Type::getUint16(); using u32tT = uint32_t; auto u32t = Type::getUint32(); using u64tT = uint64_t; auto u64t = Type::getUint64(); using f32tT = float; auto f32t = Type::getFloat32(); using f64tT = double; auto f64t = Type::getFloat64(); #define gav(t, x) getActualValue(x) interp::Value res; res.dataSize = getSizeOfType(resty); res.type = resty; #define If(at, bt) do { if(aty == (at) && bty == (bt)) { \ auto tmp = op(gav(at##T, a), gav(bt##T, b)); \ setValueRaw(is, &res, &tmp, sizeof(tmp)); \ return res; \ } } while(0) // FUCK LAH If(i8t, f32t); If(i8t, f64t); If(u8t, f32t); If(u8t, f64t); If(i16t, f32t); If(i16t, f64t); If(u16t, f32t); If(u16t, f64t); If(i32t, f32t); If(i32t, f64t); If(u32t, f32t); If(u32t, f64t); If(i64t, f32t); If(i64t, f64t); If(u64t, f32t); If(u64t, f64t); If(f32t, i8t); If(f64t, i8t); If(f32t, u8t); If(f64t, u8t); If(f32t, i16t); If(f64t, i16t); If(f32t, u16t); If(f64t, u16t); If(f32t, i32t); If(f64t, i32t); If(f32t, u32t); If(f64t, u32t); If(f32t, i64t); If(f64t, i64t); If(f32t, u64t); If(f64t, u64t); If(f32t, f32t); If(f32t, f64t); If(f64t, f32t); If(f64t, f64t); #undef If #undef gav error("interp: unsupported types '%s' and '%s'", aty, bty); } template static interp::Value twoArgumentOpIntOnly(InterpState* is, const interp::Instruction& inst, const interp::Value& a, const interp::Value& b, Functor op) { auto ret = twoArgumentOpIntOnly(is, inst.result->getType(), a, b, op); ret.val = inst.result; return ret; } template static interp::Value twoArgumentOp(InterpState* is, const interp::Instruction& inst, const interp::Value& a, const interp::Value& b, Functor op) { auto ret = twoArgumentOp(is, inst.result->getType(), a, b, op); ret.val = inst.result; return ret; } static void complainAboutFFIEscape(void* fnptr, fir::Type* fnty, const std::string& name) { if(frontend::getCanFFIEscape()) return; BareError* e = 0; if(name.empty()) { e = BareError::make("interp: cannot call external function (name unavailable; symbol address %p, function type '%s')", fnptr, fnty->str()); } else { e = BareError::make("interp: cannot call external function '%s'", name); } e->append(BareError::make(MsgType::Note, "to call external functions (ffi), pass '--ffi-escape' as a command-line flag")); e->postAndQuit(); } static interp::Value runFunctionWithLibFFI(InterpState* is, void* fnptr, fir::FunctionType* fnty, const std::vector& args, const std::string& nameIfAvailable = "") { complainAboutFFIEscape(fnptr, fnty, nameIfAvailable); // we are assuming the values in 'args' are correct! ffi_type** arg_types = new ffi_type*[args.size()]; { std::vector tmp; for(size_t i = 0; i < args.size(); i++) { tmp.push_back(convertTypeToLibFFI(args[i].type)); arg_types[i] = tmp[i]; } } ffi_type* ffi_retty = 0; ffi_cif fn_cif; { ffi_retty = convertTypeToLibFFI(fnty->getReturnType()); if(args.size() > fnty->getArgumentCount()) { iceAssert(fnty->isCStyleVarArg()); auto st = ffi_prep_cif_var(&fn_cif, FFI_DEFAULT_ABI, fnty->getArgumentCount(), args.size(), ffi_retty, arg_types); if(st != FFI_OK) error("interp: ffi_prep_cif_var failed! (%d)", st); } else { auto st = ffi_prep_cif(&fn_cif, FFI_DEFAULT_ABI, args.size(), ffi_retty, arg_types); if(st != FFI_OK) error("interp: ffi_prep_cif failed! (%d)", st); } } void** arg_pointers = new void*[args.size()]; { void** arg_values = new void*[args.size()]; // because this thing is dumb for(size_t i = 0; i < args.size(); i++) { if(args[i].dataSize <= LARGE_DATA_SIZE) arg_values[i] = reinterpret_cast(const_cast(&args[i].data[0])); } for(size_t i = 0; i < args.size(); i++) { if(args[i].dataSize <= LARGE_DATA_SIZE) arg_pointers[i] = reinterpret_cast(arg_values[i]); else arg_pointers[i] = reinterpret_cast(args[i].ptr); } delete[] arg_values; } void* ret_buffer = new uint8_t[std::max(ffi_retty->size, size_t(8))]; ffi_call(&fn_cif, reinterpret_cast(fnptr), ret_buffer, arg_pointers); interp::Value ret = { 0 }; ret.type = fnty->getReturnType(); ret.dataSize = ffi_retty->size; setValueRaw(is, &ret, ret_buffer, ret.dataSize); delete[] ret_buffer; delete[] arg_types; delete[] arg_pointers; return ret; } static interp::Value runFunctionWithLibFFI(InterpState* is, fir::Function* fn, const std::vector& args) { void* fnptr = platform::compiler::getSymbol(fn->getName().str()); if(!fnptr) error("interp: failed to find symbol named '%s'\n", fn->getName().str()); return runFunctionWithLibFFI(is, fnptr, fn->getType(), args, /* name: */ fn->getName().str()); } static interp::Value runFunctionWithLibFFI(InterpState* is, const interp::Function& fn, const std::vector& args) { void* fnptr = platform::compiler::getSymbol(fn.func->getName().str()); if(!fnptr) error("interp: failed to find symbol named '%s'\n", fn.func->getName().str()); return runFunctionWithLibFFI(is, fnptr, fn.func->getType(), args, /* name: */ fn.extFuncName); } static const interp::Block* prepareFunctionToRun(InterpState* is, const interp::Function& fn, const std::vector& args) { iceAssert(args.size() == fn.func->getArgumentCount()); // when we start a function, clear the "stack frame". is->stackFrames.push_back({ }); for(size_t i = 0; i < args.size(); i++) { auto farg = fn.func->getArguments()[i]; is->stackFrames.back().values[farg] = cloneValue(farg, args[i]); } iceAssert(!fn.blocks.empty()); auto entry = &fn.blocks[0]; is->stackFrames.back().currentFunction = &fn; is->stackFrames.back().currentBlock = entry; is->stackFrames.back().previousBlock = 0; return entry; } static void leaveFunction(InterpState* is) { auto frame = is->stackFrames.back(); for(void* alloca : frame.stackAllocs) delete[] alloca; is->stackFrames.pop_back(); } constexpr int FLOW_NORMAL = 0; constexpr int FLOW_RETURN = 1; constexpr int FLOW_BRANCH = 2; constexpr int FLOW_FNCALL = 3; constexpr int FLOW_DYCALL = 4; struct InstrResult { // for ret interp::Value returnValue; // for branches const interp::Block* targetBlk = 0; // for calls interp::Function* callTarget = 0; std::vector callArguments; fir::Value* callResultValue = 0; // for virtual calls. the args and resultvalue are shared. interp::Value virtualCallTarget; }; static int runInstruction(InterpState* is, const interp::Instruction& inst, InstrResult* instrRes); static interp::Value runBlock(InterpState* is, const interp::Block* blk) { for(size_t i = 0; i < blk->instructions.size();) { is->stackFrames.back().currentInstrIndex = i; InstrResult res; int flow = runInstruction(is, blk->instructions[i], &res); switch(flow) { case FLOW_NORMAL: { i += 1; } break; case FLOW_BRANCH: { is->stackFrames.back().previousBlock = blk; is->stackFrames.back().currentBlock = res.targetBlk; blk = res.targetBlk; i = 0; } break; case FLOW_FNCALL: { if(res.callTarget->isExternal) { is->stackFrames.back().values[res.callResultValue] = runFunctionWithLibFFI(is, *res.callTarget, res.callArguments); i += 1; } else { is->stackFrames.back().callResultOutput = res.callResultValue; auto newblk = prepareFunctionToRun(is, *res.callTarget, res.callArguments); blk = newblk; i = 0; } } break; case FLOW_DYCALL: { auto ptr = getActualValue(res.virtualCallTarget); auto firfn = reinterpret_cast(ptr); if(auto it = is->compiledFunctions.find(firfn); it != is->compiledFunctions.end()) { is->stackFrames.back().callResultOutput = res.callResultValue; auto newblk = prepareFunctionToRun(is, it->second, res.callArguments); blk = newblk; i = 0; } else { auto targ = res.virtualCallTarget; // uwu. use libffi. fir::FunctionType* fnty = 0; if(targ.type->isFunctionType()) fnty = targ.type->toFunctionType(); else if(targ.type->isPointerType() && targ.type->getPointerElementType()->isFunctionType()) fnty = targ.type->getPointerElementType()->toFunctionType(); else error("interp: call to function pointer with invalid type '%s'", targ.type); is->stackFrames.back().values[res.callResultValue] = runFunctionWithLibFFI(is, reinterpret_cast(ptr), fnty, res.callArguments, /* name: */ res.callTarget->extFuncName); i += 1; } } break; case FLOW_RETURN: { if(is->stackFrames.size() > 1) { leaveFunction(is); auto& frm = is->stackFrames.back(); res.returnValue.val = frm.callResultOutput; frm.values[frm.callResultOutput] = res.returnValue; blk = frm.currentBlock; i = frm.currentInstrIndex + 1; break; } else { return res.returnValue; } } default: { error("interp: invalid flow state"); } break; } } error("interp: invalid state"); } interp::Value InterpState::runFunction(const interp::Function& fn, const std::vector& args) { auto ffn = fn.func; if((!fn.func->isCStyleVarArg() && args.size() != fn.func->getArgumentCount()) || (fn.func->isCStyleVarArg() && args.size() < fn.func->getArgumentCount())) { error("interp: mismatched argument count in call to '%s': need %d, received %d", fn.func->getName().str(), fn.func->getArgumentCount(), args.size()); } if(fn.blocks.empty() || fn.func->isCStyleVarArg()) { // it's probably an extern! // use libffi. return runFunctionWithLibFFI(this, ffn, args); } else { auto entry = prepareFunctionToRun(this, fn, args); auto ret = runBlock(this, entry); leaveFunction(this); return ret; } } static interp::Value* getVal2(InterpState* is, fir::Value* fv) { if(auto it = is->stackFrames.back().values.find(fv); it != is->stackFrames.back().values.end()) return &it->second; else if(auto it2 = is->globals.find(fv); it2 != is->globals.end()) return &it2->second.first; else return 0; } static interp::Value getVal(InterpState* is, fir::Value* fv) { if(auto hmm = getVal2(is, fv); hmm) return *hmm; else if(auto cnst = dcast(fir::ConstantValue, fv); cnst) return makeConstant(is, cnst); else error("interp: no value with id %d", fv->id); } static interp::Value performGEP2(InterpState* is, fir::Type* resty, const interp::Value& ptr, const interp::Value& i1, const interp::Value& i2) { iceAssert(i1.type == i2.type); // so, ptr should be a pointer to an array. iceAssert(ptr.type->isPointerType() && ptr.type->getPointerElementType()->isArrayType()); auto arrty = ptr.type->getPointerElementType(); auto elmty = arrty->getArrayElementType(); auto ofs = twoArgumentOp(is, resty, i1, i2, [arrty, elmty](auto a, auto b) -> auto { return (getSizeOfType(arrty) * a) + (getSizeOfType(elmty) * b); }); auto realptr = getActualValue(ptr); auto ret = oneArgumentOp(is, resty, ofs, [realptr](auto b) -> auto { // this is not pointer arithmetic!! return realptr + b; }); ret.globalValTracker = ptr.globalValTracker; return ret; } static interp::Value performStructGEP(InterpState* is, fir::Type* resty, const interp::Value& str, uint64_t idx) { iceAssert(str.type->isPointerType()); auto strty = str.type->getPointerElementType(); if(!strty->isStructType() && !strty->isClassType() && !strty->isTupleType()) error("interp: unsupported type '%s' for struct gep", strty); std::vector elms = getTypeListOfType(strty); size_t ofs = getOffsetOfTypeInTypeList(elms, idx); uintptr_t src = getActualValue(str); src += ofs; auto ret = cloneValue(str); ret.type = resty; setValueRaw(is, &ret, &src, sizeof(src)); ret.globalValTracker = str.globalValTracker; return ret; } static interp::Value decay(const interp::Value& val) { if(val.val && val.val->islvalue()) { auto ret = loadFromPtr(val, val.val->getType()); ret.val = val.val; return ret; } else { return val; } } static interp::Value& getUndecayedArg(InterpState* is, const interp::Instruction& inst, size_t i) { iceAssert(i < inst.args.size()); auto ret = getVal2(is, inst.args[i]); iceAssert(ret); return *ret; } static interp::Value getArg(InterpState* is, const interp::Instruction& inst, size_t i) { iceAssert(i < inst.args.size()); return decay(getVal(is, inst.args[i])); } static void setRet(InterpState* is, const interp::Instruction& inst, const interp::Value& val) { is->stackFrames.back().values[inst.result] = val; } static bool areTypesSufficientlyEqual(fir::Type* a, fir::Type* b) { return a == b || (a->isPointerType() && b->isPointerType() && a->getPointerElementType() == b->getPointerElementType()); } // returns either FLOW_NORMAL, FLOW_BRANCH or FLOW_RETURN. static int runInstruction(InterpState* is, const interp::Instruction& inst, InstrResult* instrRes) { auto ok = static_cast(inst.opcode); switch(ok) { case OpKind::Signed_Add: case OpKind::Unsigned_Add: case OpKind::Floating_Add: { iceAssert(inst.args.size() == 2); auto a = getArg(is, inst, 0); auto b = getArg(is, inst, 1); iceAssert(areTypesSufficientlyEqual(a.type, b.type)); setRet(is, inst, twoArgumentOp(is, inst, a, b, [](auto a, auto b) -> decltype(a) { return a + b; })); break; } case OpKind::Signed_Sub: case OpKind::Unsigned_Sub: case OpKind::Floating_Sub: { iceAssert(inst.args.size() == 2); auto a = getArg(is, inst, 0); auto b = getArg(is, inst, 1); iceAssert(areTypesSufficientlyEqual(a.type, b.type)); setRet(is, inst, twoArgumentOp(is, inst, a, b, [](auto a, auto b) -> decltype(a) { return a - b; })); break; } case OpKind::Signed_Mul: case OpKind::Unsigned_Mul: case OpKind::Floating_Mul: { iceAssert(inst.args.size() == 2); auto a = getArg(is, inst, 0); auto b = getArg(is, inst, 1); iceAssert(areTypesSufficientlyEqual(a.type, b.type)); setRet(is, inst, twoArgumentOp(is, inst, a, b, [](auto a, auto b) -> decltype(a) { return a * b; })); break; } case OpKind::Signed_Div: case OpKind::Unsigned_Div: case OpKind::Floating_Div: { iceAssert(inst.args.size() == 2); auto a = getArg(is, inst, 0); auto b = getArg(is, inst, 1); iceAssert(areTypesSufficientlyEqual(a.type, b.type)); setRet(is, inst, twoArgumentOp(is, inst, a, b, [](auto a, auto b) -> decltype(a) { return a / b; })); break; } case OpKind::Signed_Mod: case OpKind::Unsigned_Mod: { iceAssert(inst.args.size() == 2); auto a = getArg(is, inst, 0); auto b = getArg(is, inst, 1); iceAssert(areTypesSufficientlyEqual(a.type, b.type)); setRet(is, inst, twoArgumentOpIntOnly(is, inst, a, b, [](auto a, auto b) -> decltype(a) { return a % b; })); break; } case OpKind::Floating_Mod: { iceAssert(inst.args.size() == 2); auto a = getArg(is, inst, 0); auto b = getArg(is, inst, 1); iceAssert(areTypesSufficientlyEqual(a.type, b.type)); setRet(is, inst, twoArgumentOp(is, inst, a, b, [](auto a, auto b) -> decltype(a) { return fmod(a, b); })); break; } case OpKind::ICompare_Equal: case OpKind::FCompare_Equal_ORD: case OpKind::FCompare_Equal_UNORD: { iceAssert(inst.args.size() == 2); auto a = getArg(is, inst, 0); auto b = getArg(is, inst, 1); iceAssert(areTypesSufficientlyEqual(a.type, b.type)); setRet(is, inst, twoArgumentOp(is, inst, a, b, [](auto a, auto b) -> bool { return a == b; })); break; } case OpKind::ICompare_NotEqual: case OpKind::FCompare_NotEqual_ORD: case OpKind::FCompare_NotEqual_UNORD: { iceAssert(inst.args.size() == 2); auto a = getArg(is, inst, 0); auto b = getArg(is, inst, 1); iceAssert(areTypesSufficientlyEqual(a.type, b.type)); setRet(is, inst, twoArgumentOp(is, inst, a, b, [](auto a, auto b) -> bool { return a != b; })); break; } case OpKind::ICompare_Greater: case OpKind::FCompare_Greater_ORD: case OpKind::FCompare_Greater_UNORD: { iceAssert(inst.args.size() == 2); auto a = getArg(is, inst, 0); auto b = getArg(is, inst, 1); iceAssert(areTypesSufficientlyEqual(a.type, b.type)); setRet(is, inst, twoArgumentOp(is, inst, a, b, [](auto a, auto b) -> bool { return a > b; })); break; } case OpKind::ICompare_Less: case OpKind::FCompare_Less_ORD: case OpKind::FCompare_Less_UNORD: { iceAssert(inst.args.size() == 2); auto a = getArg(is, inst, 0); auto b = getArg(is, inst, 1); iceAssert(areTypesSufficientlyEqual(a.type, b.type)); setRet(is, inst, twoArgumentOp(is, inst, a, b, [](auto a, auto b) -> bool { return a < b; })); break; } case OpKind::ICompare_GreaterEqual: case OpKind::FCompare_GreaterEqual_ORD: case OpKind::FCompare_GreaterEqual_UNORD: { iceAssert(inst.args.size() == 2); auto a = getArg(is, inst, 0); auto b = getArg(is, inst, 1); iceAssert(areTypesSufficientlyEqual(a.type, b.type)); setRet(is, inst, twoArgumentOp(is, inst, a, b, [](auto a, auto b) -> bool { return a >= b; })); break; } case OpKind::ICompare_LessEqual: case OpKind::FCompare_LessEqual_ORD: case OpKind::FCompare_LessEqual_UNORD: { iceAssert(inst.args.size() == 2); auto a = getArg(is, inst, 0); auto b = getArg(is, inst, 1); iceAssert(areTypesSufficientlyEqual(a.type, b.type)); setRet(is, inst, twoArgumentOp(is, inst, a, b, [](auto a, auto b) -> bool { return a <= b; })); break; } case OpKind::ICompare_Multi: case OpKind::FCompare_Multi: { iceAssert(inst.args.size() == 2); auto a = getArg(is, inst, 0); auto b = getArg(is, inst, 1); iceAssert(areTypesSufficientlyEqual(a.type, b.type)); setRet(is, inst, twoArgumentOp(is, inst, a, b, [](auto a, auto b) -> int { if(a == b) return 0; if(a > b) return 1; else return -1; })); break; } case OpKind::Bitwise_Xor: { iceAssert(inst.args.size() == 2); auto a = getArg(is, inst, 0); auto b = getArg(is, inst, 1); iceAssert(areTypesSufficientlyEqual(a.type, b.type)); setRet(is, inst, twoArgumentOpIntOnly(is, inst, a, b, [](auto a, auto b) -> decltype(a) { return a ^ b; })); break; } case OpKind::Bitwise_Logical_Shr: case OpKind::Bitwise_Arithmetic_Shr: { iceAssert(inst.args.size() == 2); auto a = getArg(is, inst, 0); auto b = getArg(is, inst, 1); iceAssert(a.type->isIntegerType()); setRet(is, inst, twoArgumentOpIntOnly(is, inst, a, b, [](auto a, auto b) -> decltype(a) { return a >> b; })); break; } case OpKind::Bitwise_Shl: { iceAssert(inst.args.size() == 2); auto a = getArg(is, inst, 0); auto b = getArg(is, inst, 1); iceAssert(a.type->isIntegerType()); setRet(is, inst, twoArgumentOpIntOnly(is, inst, a, b, [](auto a, auto b) -> decltype(a) { return a << b; })); break; } case OpKind::Bitwise_And: { iceAssert(inst.args.size() == 2); auto a = getArg(is, inst, 0); auto b = getArg(is, inst, 1); iceAssert(areTypesSufficientlyEqual(a.type, b.type)); setRet(is, inst, twoArgumentOpIntOnly(is, inst, a, b, [](auto a, auto b) -> decltype(a) { return a & b; })); break; } case OpKind::Bitwise_Or: { iceAssert(inst.args.size() == 2); auto a = getArg(is, inst, 0); auto b = getArg(is, inst, 1); iceAssert(areTypesSufficientlyEqual(a.type, b.type)); setRet(is, inst, twoArgumentOpIntOnly(is, inst, a, b, [](auto a, auto b) -> decltype(a) { return a | b; })); break; } case OpKind::Signed_Neg: case OpKind::Floating_Neg: { iceAssert(inst.args.size() == 1); auto a = getArg(is, inst, 0); setRet(is, inst, oneArgumentOp(is, inst, a, [](auto a) -> auto { return -1 * a; })); break; } case OpKind::Bitwise_Not: { iceAssert(inst.args.size() == 1); auto a = getArg(is, inst, 0); setRet(is, inst, oneArgumentOpIntOnly(is, inst, a, [](auto a) -> auto { return ~a; })); break; } case OpKind::Logical_Not: { iceAssert(inst.args.size() == 1); auto a = getArg(is, inst, 0); setRet(is, inst, oneArgumentOpIntOnly(is, inst, a, [](auto a) -> auto { return !a; })); break; } case OpKind::Floating_Truncate: { iceAssert(inst.args.size() == 1); auto a = getArg(is, inst, 0); auto t = inst.args[1]->getType(); interp::Value ret; if(a.type == Type::getFloat64() && t == Type::getFloat32()) ret = makeValue(inst.result, static_cast(getActualValue(a))); else if(a.type == Type::getFloat32()) ret = makeValue(inst.result, getActualValue(a)); else if(a.type == Type::getFloat64()) ret = makeValue(inst.result, getActualValue(a)); else error("interp: unsupported"); setRet(is, inst, ret); break; } case OpKind::Floating_Extend: { iceAssert(inst.args.size() == 1); auto a = getArg(is, inst, 0); auto t = inst.args[1]->getType(); interp::Value ret; if(a.type == Type::getFloat32() && t == Type::getFloat64()) ret = makeValue(inst.result, static_cast(getActualValue(a))); else if(a.type == Type::getFloat32()) ret = makeValue(inst.result, getActualValue(a)); else if(a.type == Type::getFloat64()) ret = makeValue(inst.result, getActualValue(a)); else error("interp: unsupported"); setRet(is, inst, ret); break; } case OpKind::Value_WritePtr: { iceAssert(inst.args.size() == 2); auto a = getArg(is, inst, 0); auto b = getArg(is, inst, 1); if(a.type != b.type->getPointerElementType()) error("interp: cannot write '%s' into '%s'", a.type, b.type); auto ptr = reinterpret_cast(getActualValue(b)); if(a.dataSize > LARGE_DATA_SIZE) { // just a memcopy. memmove(ptr, a.ptr, a.dataSize); } else { // still a memcopy, but slightly more involved. memmove(ptr, &a.data[0], a.dataSize); } break; } case OpKind::Value_ReadPtr: { iceAssert(inst.args.size() == 1); auto a = getArg(is, inst, 0); auto ty = a.type->getPointerElementType(); auto ret = loadFromPtr(a, ty); ret.val = inst.result; setRet(is, inst, ret); break; } case OpKind::Value_CreatePHI: { iceAssert(inst.args.size() == 1); auto phi = dcast(fir::PHINode, inst.result); iceAssert(phi); // make the empty thing first auto val = is->makeValue(inst.result); bool found = false; for(auto [ blk, v ] : phi->getValues()) { if(blk == is->stackFrames.back().previousBlock->blk) { setValue(is, &val, decay(getVal(is, v))); found = true; break; } } if(!found) error("interp: predecessor was not listed in the PHI node (id %d)!", phi->id); setRet(is, inst, val); break; } case OpKind::Value_Return: { if(!inst.args.empty()) instrRes->returnValue = getArg(is, inst, 0); return FLOW_RETURN; } case OpKind::Branch_UnCond: { iceAssert(inst.args.size() == 1); auto blk = inst.args[0]; const interp::Block* target = 0; for(const auto& b : is->stackFrames.back().currentFunction->blocks) { if(b.blk == blk) { target = &b; break; } } if(!target) error("interp: branch to block %d not in current function", blk->id); instrRes->targetBlk = target; return FLOW_BRANCH; } case OpKind::Branch_Cond: { iceAssert(inst.args.size() == 3); auto cond = getArg(is, inst, 0); iceAssert(cond.type->isBoolType()); const interp::Block* trueblk = 0; const interp::Block* falseblk = 0; for(const auto& b : is->stackFrames.back().currentFunction->blocks) { if(b.blk == inst.args[1]) trueblk = &b; else if(b.blk == inst.args[2]) falseblk = &b; if(trueblk && falseblk) break; } if(!trueblk || !falseblk) error("interp: branch to blocks %d or %d not in current function", trueblk->blk->id, falseblk->blk->id); if(getActualValue(cond)) instrRes->targetBlk = trueblk; else instrRes->targetBlk = falseblk; return FLOW_BRANCH; } case OpKind::Value_CallFunction: { iceAssert(inst.args.size() >= 1); auto fn = inst.args[0]; interp::Function* target = 0; // we probably only compiled the entry function, so if we haven't compiled the target then please do if(auto it = is->compiledFunctions.find(fn); it != is->compiledFunctions.end()) { target = &it->second; } else { for(auto f : is->module->getAllFunctions()) { if(f == fn) { target = &is->compileFunction(f); break; } } if(!target) error("interp: no function %d (name '%s')", fn->id, fn->getName().str()); } iceAssert(target); std::vector args; for(size_t i = 1; i < inst.args.size(); i++) args.push_back(getArg(is, inst, i)); instrRes->callTarget = target; instrRes->callArguments = args; instrRes->callResultValue = inst.result; return FLOW_FNCALL; } case OpKind::Value_CallFunctionPointer: { iceAssert(inst.args.size() >= 1); auto fn = getArg(is, inst, 0); std::vector args; for(size_t i = 1; i < inst.args.size(); i++) args.push_back(getArg(is, inst, i)); instrRes->callArguments = args; instrRes->virtualCallTarget = fn; instrRes->callResultValue = inst.result; return FLOW_DYCALL; } case OpKind::Value_CallVirtualMethod: { // args are: 0. classtype, 1. index, 2. functiontype, 3...N args auto clsty = inst.args[0]->getType()->toClassType(); auto fnty = inst.args[2]->getType()->toFunctionType(); iceAssert(clsty); std::vector args; for(size_t i = 3; i < inst.args.size(); i++) args.push_back(getArg(is, inst, i)); //* this is very hacky! we rely on these things not using ::val, because it's null!! auto vtable = loadFromPtr(performStructGEP(is, fir::Type::getInt8Ptr(), args[0], 0), fir::Type::getInt8Ptr()); auto vtablety = fir::ArrayType::get(fir::FunctionType::get({ }, fir::Type::getVoid())->getPointerTo(), clsty->getVirtualMethodCount()); vtable.type = vtablety->getPointerTo(); vtable = performGEP2(is, vtablety->getPointerTo(), vtable, makeConstant(is, fir::ConstantInt::getNative(0)), getArg(is, inst, 1)); auto fnptr = loadFromPtr(vtable, fnty->getPointerTo()); instrRes->callArguments = args; instrRes->virtualCallTarget = fnptr; instrRes->callResultValue = inst.result; return FLOW_DYCALL; } case OpKind::Cast_IntSize: case OpKind::Integer_ZeroExt: case OpKind::Integer_Truncate: { iceAssert(inst.args.size() == 2); auto a = getArg(is, inst, 0); auto b = getArg(is, inst, 1); interp::Value ret; if(a.type->isBoolType()) { // since we don't want to add more cases to the thingy, we do a hack -- // just get the value as a bool, then cast it to an i64 ourselves, then // pass *that* to the ops. auto boolval = static_cast(getActualValue(a)); ret = oneArgumentOp(is, inst, b, [boolval](auto b) -> auto { return static_cast(boolval); }); } else if(b.type->isBoolType()) { ret = oneArgumentOp(is, inst, a, [](auto a) -> auto { return static_cast(a); }); } else { ret = twoArgumentOp(is, inst, a, b, [](auto a, auto b) -> auto { return static_cast(a); }); } setRet(is, inst, ret); break; } // TODO: these could be made more robust!! case OpKind::Cast_Bitcast: case OpKind::Cast_Signedness: case OpKind::Cast_IntSignedness: case OpKind::Cast_PointerType: case OpKind::Cast_PointerToInt: case OpKind::Cast_IntToPointer: { iceAssert(inst.args.size() == 2); auto v = cloneValue(inst.result, getArg(is, inst, 0)); v.type = inst.args[1]->getType(); setRet(is, inst, v); break; } case OpKind::Cast_FloatToInt: { iceAssert(inst.args.size() == 2); auto a = getArg(is, inst, 0); auto b = getArg(is, inst, 1); interp::Value ret = twoArgumentOp(is, inst, a, b, [](auto a, auto b) -> auto { return static_cast(a); }); setRet(is, inst, ret); break; } case OpKind::Cast_IntToFloat: { iceAssert(inst.args.size() == 2); auto a = getArg(is, inst, 0); auto b = getArg(is, inst, 1); interp::Value ret = twoArgumentOp(is, inst, a, b, [](auto a, auto b) -> auto { return static_cast(a); }); setRet(is, inst, ret); break; } case OpKind::Value_GetPointer: { // equivalent to GEP(ptr*, index) iceAssert(inst.args.size() == 2); auto ptr = getArg(is, inst, 0); auto b = getArg(is, inst, 1); iceAssert(ptr.type->isPointerType()); iceAssert(b.type->isIntegerType()); auto elmty = ptr.type->getPointerElementType(); auto realptr = getActualValue(ptr); setRet(is, inst, oneArgumentOp(is, inst, b, [realptr, elmty](auto b) -> auto { // this doesn't do pointer arithmetic!! if it's a pointer type, the value we get // will be a uintptr_t. return realptr + (getSizeOfType(elmty) * b); })); break; } case OpKind::Value_GetGEP2: { // equivalent to GEP(ptr*, index1, index2) iceAssert(inst.args.size() == 3); auto ptr = getArg(is, inst, 0); auto i1 = getArg(is, inst, 1); auto i2 = getArg(is, inst, 2); auto ret = performGEP2(is, inst.result->getType(), ptr, i1, i2); ret.val = inst.result; setRet(is, inst, ret); break; } case OpKind::Value_GetStructMember: { // equivalent to GEP(ptr*, 0, memberIndex) iceAssert(inst.args.size() == 2); auto str = getUndecayedArg(is, inst, 0); auto idx = dcast(fir::ConstantInt, inst.args[1])->getUnsignedValue(); auto ret = performStructGEP(is, inst.result->getType()->getPointerTo(), str, idx); ret.val = inst.result; setRet(is, inst, ret); break; } case OpKind::Value_GetPointerToStructMember: { // equivalent to llvm's GEP(ptr*, ptrIndex, memberIndex) error("interp: enotsup"); } case OpKind::Misc_Sizeof: { iceAssert(inst.args.size() == 1); auto ty = inst.args[0]->getType(); auto ci = fir::ConstantInt::getNative(getSizeOfType(ty)); if(fir::getNativeWordSizeInBits() == 64) setRet(is, inst, makeValue(inst.result, static_cast(ci->getSignedValue()))); if(fir::getNativeWordSizeInBits() == 32) setRet(is, inst, makeValue(inst.result, static_cast(ci->getSignedValue()))); if(fir::getNativeWordSizeInBits() == 16) setRet(is, inst, makeValue(inst.result, static_cast(ci->getSignedValue()))); if(fir::getNativeWordSizeInBits() == 8) setRet(is, inst, makeValue(inst.result, static_cast(ci->getSignedValue()))); break; } case OpKind::Value_CreateLVal: case OpKind::Value_StackAlloc: { iceAssert(inst.args.size() == 1); auto ty = inst.args[0]->getType(); auto sz = getSizeOfType(ty); void* buffer = new uint8_t[sz]; memset(buffer, 0, sz); is->stackFrames.back().stackAllocs.push_back(buffer); auto ret = makeValueOfType(inst.result, ty->getPointerTo()); setValueRaw(is, &ret, &buffer, sizeof(void*)); setRet(is, inst, ret); break; } case OpKind::Value_Store: { iceAssert(inst.args.size() == 2); auto a = getArg(is, inst, 0); auto b = getUndecayedArg(is, inst, 1); auto ptr = reinterpret_cast(getActualValue(b)); if(a.dataSize > LARGE_DATA_SIZE) memmove(ptr, a.ptr, a.dataSize); else memmove(ptr, &a.data[0], a.dataSize); if(b.globalValTracker) { // set the modified flag to true! is->globals[b.globalValTracker].second = true; } break; } case OpKind::Value_AddressOf: { iceAssert(inst.args.size() == 1); auto ret = cloneValue(inst.result, getUndecayedArg(is, inst, 0)); setRet(is, inst, ret); break; } case OpKind::Value_Dereference: { iceAssert(inst.args.size() == 1); auto a = getArg(is, inst, 0); auto ret = cloneValue(inst.result, a); setRet(is, inst, ret); break; } case OpKind::Value_Select: { iceAssert(inst.args.size() == 3); auto cond = getArg(is, inst, 0); iceAssert(cond.type->isBoolType()); auto trueval = getArg(is, inst, 1); auto falseval = getArg(is, inst, 2); if(getActualValue(cond)) setRet(is, inst, trueval); else setRet(is, inst, falseval); break; } case OpKind::Value_InsertValue: { iceAssert(inst.args.size() == 3); auto str = getArg(is, inst, 0); auto elm = getArg(is, inst, 1); auto idx = static_cast(getActualValue(getArg(is, inst, 2))); setRet(is, inst, doInsertValue(is, inst.result, str, elm, idx)); break; } case OpKind::Value_ExtractValue: { iceAssert(inst.args.size() >= 2); auto str = getArg(is, inst, 0); auto idx = static_cast(getActualValue(getArg(is, inst, 1))); setRet(is, inst, doExtractValue(is, inst.result, str, idx)); break; } case OpKind::SAA_GetData: case OpKind::SAA_GetLength: case OpKind::SAA_GetCapacity: case OpKind::SAA_GetRefCountPtr: { iceAssert(inst.args.size() == 1); auto str = getArg(is, inst, 0); interp::Value ret; if(ok == OpKind::SAA_GetData) ret = doExtractValue(is, inst.result, str, SAA_DATA_INDEX); else if(ok == OpKind::SAA_GetLength) ret = doExtractValue(is, inst.result, str, SAA_LENGTH_INDEX); else if(ok == OpKind::SAA_GetCapacity) ret = doExtractValue(is, inst.result, str, SAA_CAPACITY_INDEX); else if(ok == OpKind::SAA_GetRefCountPtr) ret = doExtractValue(is, inst.result, str, SAA_REFCOUNTPTR_INDEX); setRet(is, inst, ret); break; } case OpKind::SAA_SetData: case OpKind::SAA_SetLength: case OpKind::SAA_SetCapacity: case OpKind::SAA_SetRefCountPtr: { iceAssert(inst.args.size() == 2); auto str = getArg(is, inst, 0); auto elm = getArg(is, inst, 1); interp::Value ret; if(ok == OpKind::SAA_SetData) ret = doInsertValue(is, inst.result, str, elm, SAA_DATA_INDEX); else if(ok == OpKind::SAA_SetLength) ret = doInsertValue(is, inst.result, str, elm, SAA_LENGTH_INDEX); else if(ok == OpKind::SAA_SetCapacity) ret = doInsertValue(is, inst.result, str, elm, SAA_CAPACITY_INDEX); else if(ok == OpKind::SAA_SetRefCountPtr) ret = doInsertValue(is, inst.result, str, elm, SAA_REFCOUNTPTR_INDEX); setRet(is, inst, ret); break; } case OpKind::ArraySlice_GetData: case OpKind::ArraySlice_GetLength: { iceAssert(inst.args.size() == 1); auto str = getArg(is, inst, 0); interp::Value ret; if(ok == OpKind::ArraySlice_GetData) ret = doExtractValue(is, inst.result, str, SLICE_DATA_INDEX); else if(ok == OpKind::ArraySlice_GetLength) ret = doExtractValue(is, inst.result, str, SLICE_LENGTH_INDEX); setRet(is, inst, ret); break; } case OpKind::ArraySlice_SetData: case OpKind::ArraySlice_SetLength: { iceAssert(inst.args.size() == 2); auto str = getArg(is, inst, 0); auto elm = getArg(is, inst, 1); interp::Value ret; if(ok == OpKind::ArraySlice_SetData) ret = doInsertValue(is, inst.result, str, elm, SLICE_DATA_INDEX); else if(ok == OpKind::ArraySlice_SetLength) ret = doInsertValue(is, inst.result, str, elm, SLICE_LENGTH_INDEX); setRet(is, inst, ret); break; } case OpKind::Any_GetData: case OpKind::Any_GetTypeID: case OpKind::Any_GetRefCountPtr: { iceAssert(inst.args.size() == 1); auto str = getArg(is, inst, 0); interp::Value ret; if(ok == OpKind::Any_GetTypeID) ret = doExtractValue(is, inst.result, str, ANY_TYPEID_INDEX); else if(ok == OpKind::Any_GetRefCountPtr) ret = doExtractValue(is, inst.result, str, ANY_REFCOUNTPTR_INDEX); else if(ok == OpKind::Any_GetData) ret = doExtractValue(is, inst.result, str, ANY_DATA_ARRAY_INDEX); setRet(is, inst, ret); break; } case OpKind::Any_SetData: case OpKind::Any_SetTypeID: case OpKind::Any_SetRefCountPtr: { iceAssert(inst.args.size() == 2); auto str = getArg(is, inst, 0); auto elm = getArg(is, inst, 1); interp::Value ret; if(ok == OpKind::Any_SetTypeID) ret = doInsertValue(is, inst.result, str, elm, ANY_TYPEID_INDEX); else if(ok == OpKind::Any_SetRefCountPtr) ret = doInsertValue(is, inst.result, str, elm, ANY_REFCOUNTPTR_INDEX); else if(ok == OpKind::Any_SetData) ret = doInsertValue(is, inst.result, str, elm, ANY_DATA_ARRAY_INDEX); setRet(is, inst, ret); break; } case OpKind::Range_GetLower: case OpKind::Range_GetUpper: case OpKind::Range_GetStep: { iceAssert(inst.args.size() == 1); auto str = getArg(is, inst, 0); interp::Value ret; if(ok == OpKind::Range_GetLower) ret = doExtractValue(is, inst.result, str, 0); else if(ok == OpKind::Range_GetUpper) ret = doExtractValue(is, inst.result, str, 1); else if(ok == OpKind::Range_GetStep) ret = doExtractValue(is, inst.result, str, 2); setRet(is, inst, ret); break; } case OpKind::Range_SetLower: case OpKind::Range_SetUpper: case OpKind::Range_SetStep: { iceAssert(inst.args.size() == 2); auto str = getArg(is, inst, 0); auto elm = getArg(is, inst, 1); interp::Value ret; if(ok == OpKind::Range_SetLower) ret = doInsertValue(is, inst.result, str, elm, 0); else if(ok == OpKind::Range_SetUpper) ret = doInsertValue(is, inst.result, str, elm, 1); else if(ok == OpKind::Range_SetStep) ret = doInsertValue(is, inst.result, str, elm, 2); setRet(is, inst, ret); break; } case OpKind::Enum_GetIndex: case OpKind::Enum_GetValue: { iceAssert(inst.args.size() == 1); auto str = getArg(is, inst, 0); interp::Value ret; if(ok == OpKind::Enum_GetIndex) ret = doExtractValue(is, inst.result, str, 0); else if(ok == OpKind::Enum_GetValue) ret = doExtractValue(is, inst.result, str, 1); setRet(is, inst, ret); break; } case OpKind::Enum_SetIndex: case OpKind::Enum_SetValue: { iceAssert(inst.args.size() == 2); auto str = getArg(is, inst, 0); auto elm = getArg(is, inst, 1); interp::Value ret; if(ok == OpKind::Enum_SetIndex) ret = doInsertValue(is, inst.result, str, elm, 0); else if(ok == OpKind::Enum_SetValue) ret = doInsertValue(is, inst.result, str, elm, 1); setRet(is, inst, ret); break; } case OpKind::Union_GetVariantID: { iceAssert(inst.args.size() == 1); auto str = getArg(is, inst, 0); setRet(is, inst, doExtractValue(is, inst.result, str, 0)); break; } case OpKind::Union_SetVariantID: { iceAssert(inst.args.size() == 2); auto str = getArg(is, inst, 0); auto elm = getArg(is, inst, 1); setRet(is, inst, doInsertValue(is, inst.result, str, elm, 0)); break; } case OpKind::Union_GetValue: { iceAssert(inst.args.size() == 2); iceAssert(inst.args[0]->getType()->isUnionType()); auto ut = inst.args[0]->getType()->toUnionType(); auto vid = dcast(fir::ConstantInt, inst.args[1])->getSignedValue(); iceAssert(static_cast(vid) < ut->getVariantCount()); auto vt = ut->getVariant(vid)->getInteriorType(); // because we can operate with the raw memory values, we can probably do this a bit more efficiently // than we can with LLVM, where we needed to create a temporary stack value to store the thing from // the extractvalue so we could cast-to-pointer then load. // first we just get the argument: auto theUnion = getArg(is, inst, 0); // then, get the array: uintptr_t arrayAddr = 0; if(theUnion.dataSize > LARGE_DATA_SIZE) arrayAddr = reinterpret_cast(theUnion.ptr); else arrayAddr = reinterpret_cast(&theUnion.data[0]); // offset it appropriately: arrayAddr += getSizeOfType(fir::Type::getNativeWord()); // ok so now we just do a 'setRaw' to get the value out. auto ret = is->makeValue(inst.result); setValueRaw(is, &ret, reinterpret_cast(arrayAddr), getSizeOfType(vt)); setRet(is, inst, ret); break; } case OpKind::Union_SetValue: { iceAssert(inst.args.size() == 3); iceAssert(inst.args[0]->getType()->isUnionType()); auto ut = inst.args[0]->getType()->toUnionType(); auto vid = static_cast(dcast(fir::ConstantInt, inst.args[1])->getSignedValue()); iceAssert(static_cast(vid) < ut->getVariantCount()); // again, we do this "manually" because we can access the raw bytes, so we don't have to // twist ourselves through hoops like with llvm. // first we just get the argument: auto theUnion = cloneValue(inst.result, getArg(is, inst, 0)); // then, get the array: uintptr_t baseAddr = 0; if(theUnion.dataSize > LARGE_DATA_SIZE) baseAddr = reinterpret_cast(theUnion.ptr); else baseAddr = reinterpret_cast(&theUnion.data[0]); // offset it appropriately: auto arrayAddr = baseAddr + getSizeOfType(fir::Type::getNativeWord()); // ok, now we just do a memcpy into the struct. iceAssert(sizeof(intptr_t) == (fir::getNativeWordSizeInBits() / CHAR_BIT)); memmove(reinterpret_cast(baseAddr), &vid, sizeof(intptr_t)); uintptr_t valueAddr = 0; auto theValue = getArg(is, inst, 2); if(theValue.dataSize > LARGE_DATA_SIZE) valueAddr = reinterpret_cast(theValue.ptr); else valueAddr = reinterpret_cast(&theValue.data[0]); memmove(reinterpret_cast(arrayAddr), reinterpret_cast(valueAddr), theValue.dataSize); setRet(is, inst, theUnion); break; } case OpKind::RawUnion_GEP: { iceAssert(inst.args.size() == 2); auto targtype = inst.args[1]->getType(); // again. just manipulate the memory. auto unn = getUndecayedArg(is, inst, 0); auto buffer = getActualValue(unn); auto ret = makeValueOfType(inst.result, targtype->getPointerTo()); setValueRaw(is, &ret, &buffer, sizeof(uintptr_t)); setRet(is, inst, ret); break; } case OpKind::Unreachable: { error("interp: unreachable op!"); } case OpKind::Invalid: default: { // note we don't use "default" to catch // new opkinds that we forget to add. error("interp: invalid opcode %d!", inst.opcode); } } return FLOW_NORMAL; } fir::ConstantValue* InterpState::unwrapInterpValueIntoConstant(const interp::Value& val) { auto ty = val.type; #define gav getActualValue auto extractOneValue = [this](const interp::Value& v, size_t idx, fir::Type* ty) -> interp::Value { auto tmp = fir::ConstantValue::getZeroValue(ty); auto x = doExtractValue(this, tmp, v, idx); delete tmp; return x; }; auto extractValueList = [this, extractOneValue](const interp::Value& v, const std::vector& tys) -> std::vector { std::vector elms; for(size_t i = 0; i < tys.size(); i++) { auto x = extractOneValue(v, i, tys[i]); elms.push_back(this->unwrapInterpValueIntoConstant(x)); } return elms; }; if(ty->isPrimitiveType() || ty->isBoolType()) { if(ty == fir::Type::getBool()) return fir::ConstantBool::get(gav(val)); else if(ty == fir::Type::getInt8()) return fir::ConstantInt::get(ty, gav(val)); else if(ty == fir::Type::getInt16()) return fir::ConstantInt::get(ty, gav(val)); else if(ty == fir::Type::getInt32()) return fir::ConstantInt::get(ty, gav(val)); else if(ty == fir::Type::getInt64()) return fir::ConstantInt::get(ty, gav(val)); else if(ty == fir::Type::getUint8()) return fir::ConstantInt::get(ty, gav(val)); else if(ty == fir::Type::getUint16()) return fir::ConstantInt::get(ty, gav(val)); else if(ty == fir::Type::getUint32()) return fir::ConstantInt::get(ty, gav(val)); else if(ty == fir::Type::getUint64()) return fir::ConstantInt::get(ty, gav(val)); else if(ty == fir::Type::getFloat32()) return fir::ConstantFP::get(ty, gav(val)); else if(ty == fir::Type::getFloat64()) return fir::ConstantFP::get(ty, gav(val)); } else if(ty->isTupleType()) { return fir::ConstantTuple::get(extractValueList(val, ty->toTupleType()->getElements())); } else if(ty->isArrayType()) { return fir::ConstantArray::get(ty, extractValueList(val, std::vector(ty->toArrayType()->getArraySize(), ty->getArrayElementType()))); } else if(ty->isCharSliceType()) { // do a bit of stuff -- extract the pointer, then the length. char* ptr = gav(extractOneValue(val, SLICE_DATA_INDEX, ty->toArraySliceType()->getDataPointerType())); int64_t len = gav(extractOneValue(val, SLICE_LENGTH_INDEX, fir::Type::getInt64())); return fir::ConstantCharSlice::get(std::string(ptr, len)); } else if(ty->isStringType()) { char* ptr = gav(extractOneValue(val, SAA_DATA_INDEX, fir::Type::getMutInt8Ptr())); int64_t len = gav(extractOneValue(val, SAA_LENGTH_INDEX, fir::Type::getInt64())); return fir::ConstantDynamicString::get(std::string(ptr, len)); } else if(ty->isArraySliceType()) { auto ptr = this->unwrapInterpValueIntoConstant(extractOneValue(val, SLICE_DATA_INDEX, ty->toArraySliceType()->getDataPointerType())); auto len = this->unwrapInterpValueIntoConstant(extractOneValue(val, SLICE_LENGTH_INDEX, fir::Type::getInt64())); return fir::ConstantArraySlice::get(ty->toArraySliceType(), ptr, len); } else if(ty->isDynamicArrayType()) { auto ptr = this->unwrapInterpValueIntoConstant(extractOneValue(val, SAA_DATA_INDEX, ty->getArrayElementType()->getMutablePointerTo())); auto len = this->unwrapInterpValueIntoConstant(extractOneValue(val, SAA_LENGTH_INDEX, fir::Type::getInt64())); auto cap = this->unwrapInterpValueIntoConstant(extractOneValue(val, SAA_CAPACITY_INDEX, fir::Type::getInt64())); return fir::ConstantDynamicArray::get(ty->toDynamicArrayType(), ptr, len, cap); } else if(ty->isStructType()) { auto sty = ty->toStructType(); std::vector vals = extractValueList(val, sty->getElements()); return fir::ConstantStruct::get(sty, vals); } #undef gav warn("interp: cannot unwrap type '%s'", ty); return fir::ConstantValue::getZeroValue(ty); } } } #ifdef _MSC_VER #pragma warning(pop) #else #pragma GCC diagnostic pop #endif ================================================ FILE: source/fir/interp/wrappers.cpp ================================================ // wrappers.cpp // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. #include "defs.h" #include "platform.h" #include "ir/module.h" #include "ir/interp.h" PLATFORM_EXPORT_FUNCTION void __interp_intrinsic_memset(void* dst, int8_t val, size_t cnt, bool) { memset(dst, val, cnt); } PLATFORM_EXPORT_FUNCTION void __interp_intrinsic_memcpy(void* dst, void* src, size_t cnt, bool) { memcpy(dst, src, cnt); } PLATFORM_EXPORT_FUNCTION void __interp_intrinsic_memmove(void* dst, void* src, size_t cnt, bool) { memmove(dst, src, cnt); } PLATFORM_EXPORT_FUNCTION int __interp_intrinsic_memcmp(void* a, void*b, size_t cnt, bool) { return memcmp(a, b, cnt); } PLATFORM_EXPORT_FUNCTION int64_t __interp_intrinsic_roundup_pow2(int64_t x) { auto num = x; auto ret = 1; while(num > 0) { num >>= 1; ret <<= 1; } return ret; } PLATFORM_EXPORT_FUNCTION int __interp_wrapper_printf(char* fmt, ...) { va_list ap; va_start(ap, fmt); int ret = vprintf(fmt, ap); va_end(ap); return ret; } PLATFORM_EXPORT_FUNCTION int __interp_wrapper_sprintf(char* buf, char* fmt, ...) { va_list ap; va_start(ap, fmt); int ret = vsprintf(buf, fmt, ap); va_end(ap); return ret; } PLATFORM_EXPORT_FUNCTION int __interp_wrapper_snprintf(char* buf, size_t n, char* fmt, ...) { va_list ap; va_start(ap, fmt); int ret = vsnprintf(buf, n, fmt, ap); va_end(ap); return ret; } PLATFORM_EXPORT_FUNCTION int __interp_wrapper_fprintf(void* stream, char* fmt, ...) { va_list ap; va_start(ap, fmt); int ret = vfprintf(static_cast(stream), fmt, ap); va_end(ap); return ret; } ================================================ FILE: source/frontend/arguments.cpp ================================================ // frontend.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "defs.h" #include "frontend.h" #include "backend.h" #define FLAX_VERSION_STRING "0.41.7-pre" #define ARG_COMPILE_ONLY "-c" #define ARG_BACKEND "-backend" #define ARG_EMIT_LLVM_IR "-emit-llvm" #define ARG_LINK_FRAMEWORK "-framework" #define ARG_FRAMEWORK_SEARCH_PATH "-F" #define ARG_HELP "--help" #define ARG_VERSION "--version" #define ARG_JITPROGRAM "-jit" #define ARG_LINK_LIBRARY "-l" #define ARG_LIBRARY_SEARCH_PATH "-L" #define ARG_MCMODEL "-mcmodel" #define ARG_OUTPUT_FILE "-o" #define ARG_OPTIMISATION_LEVEL_SELECT "-O" #define ARG_POSINDEPENDENT "-pic" #define ARG_PRINT_FIR "-print-fir" #define ARG_PRINT_LLVMIR "-print-lir" #define ARG_PROFILE "-profile" #define ARG_RUNPROGRAM "-run" #define ARG_SYSROOT "-sysroot" #define ARG_TARGET "-target" #define ARG_FFI_ESCAPE "--ffi-escape" #define ARG_FREESTANDING "--freestanding" #define ARG_NOSTDLIB "--nostdlib" #define ARG_NO_RUNTIME_CHECKS "--no-runtime-checks" #define ARG_NO_RUNTIME_ERROR_STRINGS "--no-runtime-error-strings" #define ARG_REPL "-repl" // for internal use! #define ARG_ABORT_ON_ERROR "-abort-on-error" #define WARNING_DISABLE_ALL "-w" #define WARNINGS_AS_ERRORS "-Werror" // actual warnings #define WARNING_ENABLE_UNUSED_VARIABLE "-Wunused-variable" #define WARNING_ENABLE_VARIABLE_CHECKER "-Wvar-checker" #define WARNING_DISABLE_UNUSED_VARIABLE "-Wno-unused-variable" #define WARNING_DISABLE_VARIABLE_CHECKER "-Wno-var-checker" static std::vector> helpList; static void setupMap() { helpList.push_back({ ARG_COMPILE_ONLY, "output an object file; do not call the linker" }); helpList.push_back({ ARG_BACKEND + std::string(" "), "change the backend used for compilation" }); helpList.push_back({ ARG_EMIT_LLVM_IR, "emit a bitcode (.bc) file instead of a program" }); helpList.push_back({ ARG_LINK_FRAMEWORK + std::string(" "), "link to a framework (macOS only)" }); helpList.push_back({ ARG_LINK_FRAMEWORK + std::string(" "), "link to a framework (macOS only)" }); helpList.push_back({ ARG_HELP, "print this message" }); helpList.push_back({ ARG_JITPROGRAM, "use LLVM JIT to run the program, instead of compiling to a file" }); helpList.push_back({ ARG_LINK_LIBRARY + std::string(" "), "link to a library" }); helpList.push_back({ ARG_LIBRARY_SEARCH_PATH + std::string(" "), "search for libraries in " }); helpList.push_back({ ARG_MCMODEL + std::string(" "), "change the mcmodel of the code" }); helpList.push_back({ ARG_OUTPUT_FILE + std::string(" "), "set the name of the output file" }); helpList.push_back({ ARG_OPTIMISATION_LEVEL_SELECT + std::string(""), "change the optimisation level; (-O[0-3], -Ox)" }); helpList.push_back({ ARG_FREESTANDING, "generate a freestanding executable or object file" }); helpList.push_back({ ARG_NOSTDLIB, "do not link with default libraries (libc/libm/msvcrt)" }); helpList.push_back({ ARG_FFI_ESCAPE, "allow calling external functions (eg. libc) at compile-time" }); helpList.push_back({ ARG_POSINDEPENDENT, "generate position independent code" }); helpList.push_back({ ARG_PRINT_FIR, "print the FlaxIR before compilation" }); helpList.push_back({ ARG_PRINT_LLVMIR, "print the LLVM IR before compilation" }); helpList.push_back({ ARG_PROFILE, "print internal compiler profiling statistics" }); helpList.push_back({ ARG_RUNPROGRAM, "run the program directly, instead of compiling to a file; defaults to the llvm backend" }); helpList.push_back({ ARG_SYSROOT + std::string(" "), "set the directory used as the sysroot" }); helpList.push_back({ ARG_TARGET + std::string(" "), "change the compilation target" }); helpList.push_back({ ARG_REPL, "start in repl mode" }); helpList.push_back({ WARNING_DISABLE_ALL, "disable all warnings" }); helpList.push_back({ WARNINGS_AS_ERRORS, "treat all warnings as errors" }); helpList.push_back({ ARG_NO_RUNTIME_CHECKS, "disable all runtime checks" }); helpList.push_back({ ARG_NO_RUNTIME_ERROR_STRINGS, "disable runtime error messages (program will just abort)" }); helpList.push_back({ WARNING_ENABLE_UNUSED_VARIABLE, "enable warnings for unused variables" }); helpList.push_back({ WARNING_ENABLE_VARIABLE_CHECKER, "enable warnings from the variable state checker" }); helpList.push_back({ WARNING_DISABLE_UNUSED_VARIABLE, "disable warnings for unused variables" }); helpList.push_back({ WARNING_DISABLE_VARIABLE_CHECKER, "disable warnings from the variable state checker" }); } static void printHelp() { if(helpList.empty()) setupMap(); printf("Flax Compiler - Version %s\n\n", FLAX_VERSION_STRING); printf("usage: flaxc [options] \n\n"); printf("options:\n"); size_t maxl = 0; for(const auto& p : helpList) { if(p.first.length() > maxl) maxl = p.first.length(); } maxl += 4; // ok for(const auto& [ opt, desc ] : helpList) printf(" %s%s%s\n", opt.c_str(), std::string(maxl - opt.length(), ' ').c_str(), desc.c_str()); printf("\n"); } static std::string parseQuotedString(char** argv, int& i) { std::string ret; if(strlen(argv[i]) > 0) { if(argv[i][0] == '"' || argv[i][0] == '\'') { while(std::string(argv[i]).back() != '\'' && std::string(argv[i]).back() != '"') { ret += " " + std::string(argv[i]); i++; } } else { ret = argv[i]; } } return ret; } namespace frontend { std::string getVersion() { return FLAX_VERSION_STRING; } static std::vector frameworksToLink; static std::vector frameworkSearchPaths; static std::vector librariesToLink; static std::vector librarySearchPaths; static bool _isPIC = false; static bool _isRepl = false; static bool _printFIR = false; static bool _ffiEscape = false; static bool _doProfiler = false; static bool _printLLVMIR = false; static bool _abortOnError = false; static bool _isFreestanding = false; static bool _noStandardLibraries = false; static bool _noRuntimeChecks = false; static bool _noRuntimeErrorStrings = false; static std::string _mcModel; static std::string _targetArch; static std::string _sysrootPath; static const std::string _prefixPath = "/usr/local/"; using BackendOption = backend::BackendOption; using ProgOutputMode = backend::ProgOutputMode; using OptimisationLevel = backend::OptimisationLevel; static auto _optLevel = OptimisationLevel::Normal; static auto _outputMode = ProgOutputMode::Program; static auto _backendCodegen = BackendOption::LLVM; OptimisationLevel getOptLevel() { return _optLevel; } ProgOutputMode getOutputMode() { return _outputMode; } BackendOption getBackendOption() { return _backendCodegen; } bool getPrintProfileStats() { return _doProfiler; } bool getIsNoRuntimeChecks() { return _noRuntimeChecks; } bool getIsNoRuntimeErrorStrings() { return _noRuntimeErrorStrings; } bool getAbortOnError() { return _abortOnError; } bool getCanFFIEscape() { return _ffiEscape; } bool getIsReplMode() { return _isRepl; } bool getPrintFIR() { return _printFIR; } bool getPrintLLVMIR() { return _printLLVMIR; } std::vector getFrameworksToLink() { return frameworksToLink; } std::vector getFrameworkSearchPaths() { return frameworkSearchPaths; } std::vector getLibrariesToLink() { return librariesToLink; } std::vector getLibrarySearchPaths() { return librarySearchPaths; } bool getIsFreestanding() { return _isFreestanding; } bool getIsNoStandardLibraries() { return _noStandardLibraries; } bool getIsPositionIndependent() { return _isPIC; } std::string getParameter(const std::string& name) { if(name == "mcmodel") return _mcModel; else if(name == "targetarch") return _targetArch; else if(name == "sysroot") return _sysrootPath; else if(name == "prefix") return _prefixPath; else iceAssert("invalid"); return ""; } // nothing to do with synchronisation!! // TODO: this is a bit dumb given our current boolean flags, but... meh static std::unordered_set setOptions; static util::hash_map> mutualExclusions; static void setupFlagMutexes() { // repl is basically incompatible with everything, so list it first. mutualExclusions[ARG_REPL].insert(ARG_RUNPROGRAM); mutualExclusions[ARG_REPL].insert(ARG_TARGET); mutualExclusions[ARG_REPL].insert(ARG_BACKEND); mutualExclusions[ARG_REPL].insert(ARG_MCMODEL); mutualExclusions[ARG_REPL].insert(ARG_JITPROGRAM); mutualExclusions[ARG_REPL].insert(ARG_OUTPUT_FILE); mutualExclusions[ARG_REPL].insert(ARG_COMPILE_ONLY); mutualExclusions[ARG_REPL].insert(ARG_FREESTANDING); mutualExclusions[ARG_REPL].insert(ARG_POSINDEPENDENT); mutualExclusions[ARG_REPL].insert(ARG_OPTIMISATION_LEVEL_SELECT); // don't try to run/jit and compile/output at the same time mutualExclusions[ARG_RUNPROGRAM].insert(ARG_TARGET); mutualExclusions[ARG_RUNPROGRAM].insert(ARG_MCMODEL); mutualExclusions[ARG_RUNPROGRAM].insert(ARG_OUTPUT_FILE); mutualExclusions[ARG_RUNPROGRAM].insert(ARG_COMPILE_ONLY); mutualExclusions[ARG_RUNPROGRAM].insert(ARG_FREESTANDING); mutualExclusions[ARG_RUNPROGRAM].insert(ARG_POSINDEPENDENT); // just copy it. mutualExclusions[ARG_JITPROGRAM] = mutualExclusions[ARG_RUNPROGRAM]; // ok now the trick is, for each exclusion, add the reverse. for(const auto& [ x, xs ] : mutualExclusions) for(const auto& y : xs) mutualExclusions[y].insert(x); } static void checkOptionExclusivity(const std::string& a) { for(const auto& ex : mutualExclusions[a]) { if(setOptions.find(ex) != setOptions.end()) _error_and_exit("error: options '%s' and '%s' are mutually exclusive", a, ex); } } std::pair parseCmdLineOpts(int argc, char** argv) { setupFlagMutexes(); // quick thing: usually programs will not do anything if --help or --version is anywhere in the flags. for(int i = 1; i < argc; i++) { if(!strcmp(argv[i], ARG_HELP)) { printHelp(); exit(0); } else if(!strcmp(argv[i], ARG_VERSION)) { printf("Flax Compiler (flaxc), version %s\n", FLAX_VERSION_STRING); exit(0); } } // parse arguments std::vector filenames; std::string outname; if(argc > 1) { // parse the command line opts for(int i = 1; i < argc; i++) { bool wasFilename = false; if(!strcmp(argv[i], ARG_LINK_FRAMEWORK)) { if(i != argc - 1) { i++; frameworksToLink.push_back(argv[i]); continue; } else { _error_and_exit("error: expected framework name after '-framework' option\n"); } } else if(!strcmp(argv[i], ARG_FRAMEWORK_SEARCH_PATH)) { if(i != argc - 1) { i++; frameworkSearchPaths.push_back(argv[i]); continue; } else { _error_and_exit("error: expected path after '-F' option\n"); } } else if(strstr(argv[i], ARG_LINK_LIBRARY) == argv[i]) { // handles -lfoo if(strlen(argv[i]) > strlen(ARG_LINK_LIBRARY)) { argv[i] += strlen(ARG_LINK_LIBRARY); librariesToLink.push_back(parseQuotedString(argv, i)); continue; } else { _error_and_exit("error: expected library name after '-l' option\n"); } } else if(!strcmp(argv[i], ARG_LINK_LIBRARY)) { // handles -l foo if(i != argc - 1) { i++; librariesToLink.push_back(argv[i]); continue; } else { _error_and_exit("error: expected library name after '-l' option\n"); } } else if(strstr(argv[i], ARG_LIBRARY_SEARCH_PATH) == argv[i]) { // handles -Lpath if(strlen(argv[i]) > strlen(ARG_LIBRARY_SEARCH_PATH)) { argv[i] += strlen(ARG_LIBRARY_SEARCH_PATH); librarySearchPaths.push_back(parseQuotedString(argv, i)); continue; } else { _error_and_exit("error: expected path after '-L' option\n"); } } else if(!strcmp(argv[i], ARG_LIBRARY_SEARCH_PATH)) { // handles -L path if(i != argc - 1) { i++; librarySearchPaths.push_back(argv[i]); continue; } else { _error_and_exit("error: expected path after '-L' option\n"); } } else if(!strcmp(argv[i], ARG_SYSROOT)) { if(i != argc - 1) { i++; frontend::_sysrootPath = parseQuotedString(argv, i); continue; } else { _error_and_exit("error: expected directory name after '-sysroot' option\n"); } } if(!strcmp(argv[i], ARG_TARGET)) { if(i != argc - 1) { i++; frontend::_targetArch = parseQuotedString(argv, i); continue; } else { _error_and_exit("error: expected target string after '-target' option\n"); } } else if(!strcmp(argv[i], ARG_FREESTANDING)) { // set freestanding mode frontend::_isFreestanding = true; } else if(!strcmp(argv[i], ARG_NO_RUNTIME_CHECKS)) { frontend::_noRuntimeChecks = true; } else if(!strcmp(argv[i], ARG_NO_RUNTIME_ERROR_STRINGS)) { frontend::_noRuntimeErrorStrings = true; } else if(!strcmp(argv[i], ARG_FFI_ESCAPE)) { frontend::_ffiEscape = true; } else if(!strcmp(argv[i], ARG_REPL)) { frontend::_isRepl = true; } else if(!strcmp(argv[i], ARG_BACKEND)) { if(i != argc - 1) { i++; auto str = parseQuotedString(argv, i); if(str == "llvm") { frontend::_backendCodegen = BackendOption::LLVM; } else if(str == "interp") { frontend::_backendCodegen = BackendOption::Interpreter; } else if(str == "x64asm") { frontend::_backendCodegen = BackendOption::Assembly_x64; } else if(str == "none") { frontend::_backendCodegen = BackendOption::None; } else { _error_and_exit("error: '%s' is not a valid backend (valid options are 'llvm' and 'x64asm')\n", str); } continue; } else { _error_and_exit("error: expected backend name after '-backend' option\n"); } } else if(!strcmp(argv[i], ARG_OUTPUT_FILE)) { if(i != argc - 1) { i++; outname = parseQuotedString(argv, i); continue; } else { _error_and_exit("error: expected filename name after '-o' option\n"); } } else if(!strcmp(argv[i], ARG_POSINDEPENDENT)) { frontend::_isPIC = true; } else if(!strcmp(argv[i], ARG_PROFILE)) { frontend::_doProfiler = true; } else if(!strcmp(argv[i], ARG_MCMODEL)) { if(i != argc - 1) { i++; std::string mm = parseQuotedString(argv, i); if(mm != "kernel" && mm != "small" && mm != "medium" && mm != "large") { _error_and_exit("error: valid options for '-mcmodel' are 'small', 'medium', 'large' and 'kernel'.\n"); } frontend::_mcModel = mm; } else { _error_and_exit("error: expected mcmodel name after '-mcmodel' option\n"); } } else if(!strcmp(argv[i], WARNINGS_AS_ERRORS)) { // frontend::Flags |= (uint64_t) frontend::Flag::WarningsAsErrors; } else if(!strcmp(argv[i], WARNING_DISABLE_ALL)) { // frontend::Flags |= (uint64_t) frontend::Flag::NoWarnings; } else if(!strcmp(argv[i], ARG_PRINT_LLVMIR)) { frontend::_printLLVMIR = true; } else if(!strcmp(argv[i], ARG_PRINT_FIR)) { frontend::_printFIR = true; } else if(!strcmp(argv[i], ARG_COMPILE_ONLY)) { if(frontend::_outputMode != ProgOutputMode::RunJit && frontend::_outputMode != ProgOutputMode::LLVMBitcode) { frontend::_outputMode = ProgOutputMode::ObjectFile; } } else if(!strcmp(argv[i], ARG_JITPROGRAM) || !strcmp(argv[i], ARG_RUNPROGRAM)) { if(frontend::_outputMode != ProgOutputMode::ObjectFile && frontend::_outputMode != ProgOutputMode::LLVMBitcode) { frontend::_outputMode = ProgOutputMode::RunJit; } } else if(strstr(argv[i], ARG_OPTIMISATION_LEVEL_SELECT) == argv[i]) { // make sure we have at least 3 chars if(strlen(argv[i]) < 3) { _error_and_exit("error: '-O' is not a valid option on its own\n"); } else if(strlen(argv[i]) > 3) { _error_and_exit("error: '%s' is not a valid option\n", argv[i]); } if(argv[i][2] == 'x') { // literally nothing frontend::_optLevel = OptimisationLevel::Debug; } else { switch(argv[i][2]) { case '0': frontend::_optLevel = OptimisationLevel::None; break; case '1': frontend::_optLevel = OptimisationLevel::Minimal; break; case '2': frontend::_optLevel = OptimisationLevel::Normal; break; case '3': frontend::_optLevel = OptimisationLevel::Aggressive; break; default: _error_and_exit("error: '%c' is not a valid optimisation level (must be between 0 and 3)\n", argv[i][2]); } } } else if(!strcmp(argv[i], ARG_ABORT_ON_ERROR)) { frontend::_abortOnError = true; } // warnings. else if(!strcmp(argv[i], WARNING_DISABLE_UNUSED_VARIABLE)) { // frontend::setWarning(frontend::Warning::UnusedVariable, false); } else if(!strcmp(argv[i], WARNING_ENABLE_UNUSED_VARIABLE)) { // frontend::setWarning(frontend::Warning::UnusedVariable, true); } else if(!strcmp(argv[i], WARNING_DISABLE_VARIABLE_CHECKER)) { // frontend::setWarning(frontend::Warning::UseAfterFree, false); // frontend::setWarning(frontend::Warning::UseBeforeAssign, false); } else if(!strcmp(argv[i], WARNING_ENABLE_VARIABLE_CHECKER)) { // frontend::setWarning(frontend::Warning::UseAfterFree, true); // frontend::setWarning(frontend::Warning::UseBeforeAssign, true); } else if(argv[i][0] == '-') { _error_and_exit("error: unrecognised option '%s'\n", argv[i]); } else { wasFilename = true; filenames.push_back(argv[i]); } if(!wasFilename) { setOptions.insert(argv[i]); checkOptionExclusivity(argv[i]); } } } if(filenames.empty() && !frontend::_isRepl) _error_and_exit("error: no input files\n"); if(filenames.size() > 1) _error_and_exit("only one input file is supported at the moment\n"); return { filenames.empty() ? "" : filenames[0], outname }; } } ================================================ FILE: source/frontend/collector.cpp ================================================ // collector.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include #include #include "errors.h" #include "codegen.h" #include "frontend.h" #include "typecheck.h" namespace frontend { void collectFiles(const std::string& _filename, CollectorState* state) { // first, collect and parse the first file std::string full = getFullPathOfFile(_filename); auto graph = new DependencyGraph(); util::hash_map visited; state->allFiles = checkForCycles(full, buildDependencyGraph(graph, full, visited)); state->fullMainFile = full; state->graph = graph; // pre-lex everything. for(const auto& f : state->allFiles) { frontend::getFileTokens(f); state->totalLinesOfCode += frontend::getFileLines(frontend::getFileIDFromFilename(f)).size(); } } void parseFiles(CollectorState* state) { // parse for(const auto& file : state->allFiles) { // parse it all auto opers = parser::parseOperators(frontend::getFileTokens(file)); { // TODO: clean this up maybe. auto checkDupes = [](const util::hash_map& existing, const util::hash_map& newops, const std::string& kind) { for(const auto& op : newops) { if(auto it = existing.find(op.first); it != existing.end()) { SimpleError::make(op.second.loc, "duplicate declaration for %s operator '%s'", kind, op.second.symbol) ->append(SimpleError::make(MsgType::Note, it->second.loc, "previous declaration was here:")) ->postAndQuit(); } } }; checkDupes(state->binaryOps, std::get<0>(opers), "infix"); checkDupes(state->prefixOps, std::get<1>(opers), "prefix"); checkDupes(state->postfixOps, std::get<2>(opers), "postfix"); for(const auto& op : std::get<0>(opers)) state->binaryOps[op.first] = op.second; for(const auto& op : std::get<1>(opers)) state->prefixOps[op.first] = op.second; for(const auto& op : std::get<2>(opers)) state->postfixOps[op.first] = op.second; } state->parsed[file] = parser::parseFile(file, frontend::getFileState(file), *state); } } sst::DefinitionTree* typecheckFiles(CollectorState* state) { // do a simple thing. if(state->nativeWordSize != 0) fir::setNativeWordSizeInBits(state->nativeWordSize); else fir::setNativeWordSizeInBits(64); // typecheck for(const auto& file : state->allFiles) { // note that we're guaranteed (because that's the whole point) // that any module we encounter here will have had all of its dependencies checked already std::vector> imports; for(auto d : state->graph->getDependenciesOf(file)) { auto imported = d->to; auto dtree = state->dtrees[imported->name]; iceAssert(dtree); ImportThing ithing { imported->name, d->ithing.importAs, d->ithing.pubImport, d->ithing.loc }; if(auto it = std::find_if(imports.begin(), imports.end(), [&ithing](const auto& x) -> bool { return x.first.name == ithing.name; }); it != imports.end()) { SimpleError::make(ithing.loc, "importing previously imported module '%s'", ithing.name) ->append(SimpleError::make(MsgType::Note, it->first.loc, "previous import was here:")) ->postAndQuit(); } imports.push_back({ ithing, dtree }); } // i guess we always add prelude definitions? state->dtrees[file] = sst::typecheck(state, state->parsed[file], imports, /* addPreludeDefinitions: */ true); } return state->dtrees[state->fullMainFile]; } fir::Module* generateFIRModule(CollectorState* state, sst::DefinitionTree* maintree) { iceAssert(maintree && maintree->topLevel); for(const auto& dt : state->dtrees) { for(const auto& def : dt.second->typeDefnMap) { if(auto it = maintree->typeDefnMap.find(def.first); it != maintree->typeDefnMap.end()) iceAssert(it->second == def.second); maintree->typeDefnMap[def.first] = def.second; } } return cgn::codegen(maintree); } } ================================================ FILE: source/frontend/dependencies.cpp ================================================ // dependencies.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "errors.h" #include "frontend.h" namespace frontend { static void stronglyConnect(DependencyGraph* graph, int& index, std::vector>& connected, DepNode* node); void DependencyGraph::addModuleDependency(const std::string& from, const std::string& to, const ImportThing& ithing) { // find existing node DepNode* src = 0; DepNode* dst = 0; for(auto d : this->nodes) { if(!src && d->name == from) { src = d; } else if(!dst && d->name == to) { dst = d; } } if(!src) { src = new DepNode(); src->name = from; this->nodes.push_back(src); } if(!dst) { dst = new DepNode(); dst->name = to; this->nodes.push_back(dst); } dst->users.push_back({ src, ithing.loc }); Dep* d = new Dep(); d->from = src; d->to = dst; d->ithing = ithing; this->edgesFrom[src].push_back(d); } std::vector> DependencyGraph::findCyclicDependencies() { int index = 0; std::vector> ret; for(auto n : this->nodes) { n->index = -1; n->onStack = false; n->lowlink = -1; } for(auto n : this->nodes) { if(n->index == -1) stronglyConnect(this, index, ret, n); } return ret; } std::vector DependencyGraph::getDependenciesOf(const std::string& name) { DepNode* node = 0; for(auto n : this->nodes) { if(n->name == name) { node = n; break; } } if(!node) return { }; return this->edgesFrom[node]; } static void stronglyConnect(DependencyGraph* graph, int& index, std::vector>& connected, DepNode* node) { node->index = index; node->lowlink = index; index++; graph->stack.push(node); node->onStack = true; std::vector edges = graph->edgesFrom[node]; for(auto edge : edges) { DepNode* w = edge->to; if(w->index == -1) { stronglyConnect(graph, index, connected, w); node->lowlink = (node->lowlink < w->lowlink ? node->lowlink : w->lowlink); } else if(w->onStack) { node->lowlink = (node->lowlink < w->index ? node->lowlink : w->index); } } if(node->lowlink == node->index) { std::vector set; while(true) { DepNode* w = graph->stack.top(); graph->stack.pop(); w->onStack = false; set.push_back(w); if(w == node) break; } connected.push_back(set); } } std::vector checkForCycles(const std::string& topmod, frontend::DependencyGraph* graph) { auto groups = graph->findCyclicDependencies(); for(const auto& grp : groups) { if(grp.size() > 1) { std::string modlist; std::vector locs; for(auto m : grp) { std::string fn = getFilenameFromPath(m->name); fn = fn.substr(0, fn.find_last_of('.')); modlist += " " + fn + "\n"; } info("cyclic import dependencies between these modules:\n%s", modlist.c_str()); info("offending import statements:"); for(auto m : grp) { for(auto u : m->users) { info(u.second, ""); } } error("cyclic dependencies found, cannot continue"); } } if(groups.size() == 0) { frontend::DepNode* dn = new frontend::DepNode(); dn->name = topmod; groups.insert(groups.begin(), { dn }); } std::vector fulls; for(auto grp : groups) { // make sure it's 1 iceAssert(grp.size() == 1); fulls.push_back(frontend::getFullPathOfFile(grp[0]->name)); } return fulls; } frontend::DependencyGraph* buildDependencyGraph(frontend::DependencyGraph* graph, const std::string& full, util::hash_map& visited) { auto tokens = frontend::getFileTokens(full); auto imports = parser::parseImports(full, tokens); // get the proper import of each 'import' std::vector fullpaths; for(const auto& imp : imports) { auto tovisit = resolveImport(imp.name, imp.loc, full); graph->addModuleDependency(full, tovisit, imp); if(!visited[tovisit]) { visited[tovisit] = true; buildDependencyGraph(graph, tovisit, visited); } } return graph; } } ================================================ FILE: source/frontend/errors.cpp ================================================ // errors.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "defs.h" #include "errors.h" #include "ast.h" #include "sst.h" #include "frontend.h" #include "memorypool.h" #define LEFT_PADDING TAB_WIDTH static std::string repeat(std::string str, size_t n) { if(n == 0) { str.clear(); str.shrink_to_fit(); return str; } else if(n == 1 || str.empty()) { return str; } auto period = str.size(); if(period == 1) { str.append(n - 1, str.front()); return str; } str.reserve(period * n); size_t m = 2; for(; m < n; m *= 2) str += str; str.append(str.c_str(), (n - (m / 2)) * period); return str; } static std::string spaces(size_t n) { return repeat(" ", n); } static std::string fetchContextLine(Location loc, size_t* adjust) { if(loc.fileID == 0) return ""; const auto& lines = frontend::getFileLines(loc.fileID); if(lines.size() > loc.line) { std::stringstream ln; auto orig = std::string(lines[loc.line]); // skip all leading whitespace. bool ws = true; for(auto c : orig) { if(ws && c == '\t') { *adjust += TAB_WIDTH; continue; } else if(ws && c == ' ') { *adjust += 1; continue; } else if(c == '\n') { break; } else { ws = false; ln << c; } } return strprintf("%s%s", spaces(LEFT_PADDING), ln.str().c_str()); } return ""; } // #define UNDERLINE_CHARACTER "^" #define UNDERLINE_CHARACTER "\u203e" static std::string getSpannedContext(const Location& loc, const std::vector& spans, size_t* adjust, size_t* num_width, size_t* margin, bool underline, bool bottompad, const std::string& underlineColour, const std::string& overrideLineContent) { std::string ret; iceAssert(adjust && margin && num_width); iceAssert((underline == bottompad || bottompad) && "cannot underline without bottom pad"); if(!std::is_sorted(spans.begin(), spans.end(), [](const auto& a, const auto& b) -> bool { return a.loc.col < b.loc.col; })) _error_and_exit("spans must be sorted!\n"); *num_width = std::to_string(loc.line + 1).length(); // one spacing line *margin = *num_width + 2; ret += strprintf("%s |\n", spaces(*num_width)); if(overrideLineContent.empty()) ret += strprintf("%d |%s\n", loc.line + 1, fetchContextLine(loc, adjust)); else ret += strprintf("%s |%s%s\n", spaces(*num_width), spaces(LEFT_PADDING), overrideLineContent); if(bottompad) ret += strprintf("%s |", spaces(*num_width)); // ok, now loop through each err, and draw the underline. if(underline) { //* cursor represents the 'virtual' position -- excluding the left margin size_t cursor = 0; // columns actually start at 1 for some reason. ret += spaces(LEFT_PADDING - 1); for(const auto& span : spans) { std::string underliner; if(span.msg.empty()) underliner = repeat(span.loc.len < 3 ? "^" : UNDERLINE_CHARACTER, span.loc.len); else underliner = "\u0305|" + repeat(UNDERLINE_CHARACTER, span.loc.len - 1); // pad out. auto tmp = strprintf("%s", spaces(1 + span.loc.col - *adjust - cursor)); cursor += tmp.length(); ret += tmp + strprintf("%s", span.colour.empty() ? underlineColour : span.colour); tmp = strprintf("%s", underliner); cursor += span.loc.len; ret += tmp + strprintf("%s", COLOUR_RESET); } } return ret; } static std::string getSingleContext(const Location& loc, const std::string& underlineColour = COLOUR_RED_BOLD, const std::string& overrideLineContent = "", bool underline = true, bool bottompad = true) { if(loc.fileID == 0 && overrideLineContent.empty()) return ""; size_t a = 0; size_t b = 0; size_t c = 0; return getSpannedContext(loc, { util::ESpan(loc, "") }, &a, &b, &c, underline, bottompad, underlineColour, overrideLineContent); } std::string __error_gen_internal(const Location& loc, const std::string& msg, const char* type, bool context, bool multipart) { std::string ret; auto colour = COLOUR_RED_BOLD; if(strcmp(type, "warning") == 0) colour = COLOUR_MAGENTA_BOLD; else if(strcmp(type, "note") == 0) colour = COLOUR_GREY_BOLD; // bool empty = strcmp(type, "") == 0; // bool dobold = strcmp(type, "note") != 0; //? do we want to truncate the file path? //? we're doing it now, might want to change (or use a flag) std::string filename = frontend::getFilenameFromPath(loc.fileID == 0 ? "(unknown)" : frontend::getFilenameFromID(loc.fileID)); ret += strprintf("%s%s%s:%s %s\n", COLOUR_RESET, colour, type, COLOUR_RESET, msg); if(loc.fileID > 0) { auto location = strprintf("%s:%d:%d", filename, loc.line + 1, loc.col + 1); ret += strprintf("%s%sat:%s %s%s\n", COLOUR_RESET, COLOUR_GREY_BOLD, spaces(strlen(type) - 2), COLOUR_RESET, location); } if(context && loc.fileID > 0) { auto underlineColour = COLOUR_RED_BOLD; if(strcmp(type, "note") == 0) underlineColour = COLOUR_BLUE_BOLD; ret += getSingleContext(loc, underlineColour) + "\n"; } if(!multipart) ret += "\n"; return ret; } static std::string typestr(MsgType t) { switch(t) { case MsgType::Note: return "note"; case MsgType::Error: return "error"; case MsgType::Warning: return "warning"; default: iceAssert(0); return ""; } } template static size_t strprinterrf(const char* fmt, Ts... ts) { return static_cast(fprintf(stderr, "%s", strprintf(fmt, ts...).c_str())); } // template static void outputWithoutContext(const char* type, const Location& loc, const char* s, bool multi) { strprinterrf("%s", __error_gen_internal(loc, s, type, false, multi)); } void BareError::post() { if(!this->msg.empty()) outputWithoutContext(typestr(this->type).c_str(), Location(), this->msg.c_str(), !this->subs.empty()); for(auto other : this->subs) other->post(); } void SimpleError::post() { if(!this->msg.empty()) { outputWithoutContext(typestr(this->type).c_str(), this->loc, this->msg.c_str(), true); strprinterrf("%s%s%s", this->wordsBeforeContext, this->wordsBeforeContext.size() > 0 ? "\n" : "", this->printContext ? getSingleContext(this->loc, this->type == MsgType::Note ? COLOUR_BLUE_BOLD : COLOUR_RED_BOLD) + "\n" : ""); } for(auto other : this->subs) other->post(); } void ExampleMsg::post() { outputWithoutContext(typestr(this->type).c_str(), Location(), "for example:", !this->subs.empty()); strprinterrf("%s\n\n", getSingleContext(Location(), COLOUR_BLUE_BOLD, this->example)); for(auto other : this->subs) other->post(); } namespace util { static bool operator == (const util::ESpan& a, const util::ESpan& b) { return a.loc == b.loc && a.msg == b.msg; } BareError* make_BareError(const std::string& m, MsgType t) { return util::pool(m, t); } SpanError* make_SpanError(SimpleError* se, const std::vector& s, MsgType t) { return util::pool(se, s, t); } SimpleError* make_SimpleError(const Location& l, const std::string& m, MsgType t) { return util::pool(l, m, t); } OverloadError* make_OverloadError(SimpleError* se, MsgType t) { return util::pool(se, t); } ExampleMsg* make_ExampleMsg(const std::string& eg, MsgType t) { return util::pool(eg, t); } } SpanError* SpanError::add(const util::ESpan& s) { this->spans.push_back(s); return this; } void SpanError::post() { this->top->printContext = false; this->top->post(); { size_t adjust = 0; size_t margin = 0; size_t num_width = 0; bool didExtra = false; if(this->highlightActual && std::find_if(this->spans.begin(), this->spans.end(), [this](const util::ESpan& s) -> bool { return s.loc == this->top->loc; }) == this->spans.end()) { didExtra = true; auto sp = util::ESpan(this->top->loc, ""); sp.colour = COLOUR_RED_BOLD; this->spans.push_back(sp); } std::sort(this->spans.begin(), this->spans.end(), [](const auto& a, const auto& b) -> bool { return a.loc.col < b.loc.col; }); this->spans.erase(std::unique(this->spans.begin(), this->spans.end()), this->spans.end()); strprinterrf("%s\n", getSpannedContext(this->top->loc, this->spans, &adjust, &num_width, &margin, true, true, COLOUR_CYAN_BOLD, "")); // ok now remove the extra thing. if(didExtra) this->spans.erase(std::find(this->spans.begin(), this->spans.end(), util::ESpan(this->top->loc, ""))); size_t cursor = 0; size_t width = static_cast(0.85 * platform::getTerminalWidth()); // there's probably a more efficient way to do this, but since we're throwing an error and already going to die, // it doesn't really matter. // don't mutate the spans, make a copy auto spanscopy = this->spans; size_t counter = 0; while(counter < spanscopy.size()) { strprinterrf("%s", spaces(margin)); for(size_t i = 0; i < spanscopy.size() - counter; i++) { auto col = spanscopy[i].loc.col; if(i == spanscopy.size() - counter - 1) { auto remaining = spanscopy[i].msg; // complex math shit to predict where the cursor will be once we print, // and more importantly whether or not we'll finish printing the message in the current iteration. auto realcursor = margin + col; auto splitpos = std::min(remaining.length(), width - realcursor); // refuse to split words in half. while(splitpos > 0 && splitpos < remaining.length() && remaining[splitpos - 1] != ' ') splitpos--; auto segment = remaining.substr(0, splitpos); if(segment.empty()) { counter++; break; } else { cursor += 3 + strprinterrf("%s", spaces((LEFT_PADDING - 1) + 1 + col - adjust - cursor)); strprinterrf("%s|>%s ", COLOUR_CYAN_BOLD, COLOUR_RESET); spanscopy[i].msg = remaining.substr(segment.length()); cursor += strprinterrf("%s", segment); } } else { cursor += 1 + strprinterrf("%s", spaces((LEFT_PADDING - 1) + 1 + col - adjust - cursor)); strprinterrf("%s|%s", COLOUR_CYAN_BOLD, COLOUR_RESET); } } cursor = 0; strprinterrf("\n"); } } for(auto other : this->subs) other->post(); } void OverloadError::clear() { this->cands.clear(); this->top = 0; } OverloadError& OverloadError::addCand(Locatable* d, ErrorMsg* sp) { this->cands[d] = sp; return *this; } void OverloadError::post() { // first, post the original error. this->top->wordsBeforeContext = "(call site)"; this->top->post(); // sort the candidates by line number // (idk maybe it's a windows thing but it feels like the order changes every so often) auto cds = std::vector>(this->cands.begin(), this->cands.end()); std::sort(cds.begin(), cds.end(), [](auto a, auto b) -> bool { return a.first->loc.line < b.first->loc.line; }); // go through each candidate. int cand_counter = 1; for(auto [ loc, emg ] : cds) { if(emg->kind != ErrKind::Span) { emg->type = MsgType::Note; emg->post(); } else { auto spe = dcast(SpanError, emg); iceAssert(spe); spe->top = SimpleError::make(MsgType::Note, loc->loc, "candidate %d was defined here:", cand_counter++); spe->highlightActual = false; spe->post(); } } for(auto sub : this->subs) sub->post(); } [[noreturn]] void doTheExit(bool trace) { fprintf(stderr, "\nthere were errors, compilation cannot continue\n"); if(frontend::getAbortOnError()) abort(); else exit(-1); } ================================================ FILE: source/frontend/file.cpp ================================================ // file.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include #include #include #include #include #include #include #include "lexer.h" #include "errors.h" #include "frontend.h" namespace frontend { static util::hash_map fileList; static void getRawLines(const std::string_view& fileContents, bool* crlf, util::FastInsertVector* rawlines) { std::string_view view = fileContents; bool first = true; while(true) { size_t ln = 0; if(first || *crlf) { ln = view.find("\r\n"); if(ln != std::string_view::npos && first) *crlf = true; } if((!first && !*crlf) || (first && !*crlf && ln == std::string_view::npos)) ln = view.find('\n'); first = false; if(ln != std::string_view::npos) { new (rawlines->getNextSlotAndIncrement()) std::string_view(view.data(), ln + (*crlf ? 2 : 1)); view.remove_prefix(ln + (*crlf ? 2 : 1)); } else { break; } } // account for the case when there's no trailing newline, and we still have some stuff stuck in the view. if(!view.empty()) { new (rawlines->getNextSlotAndIncrement()) std::string_view(view.data(), view.length()); } } static void tokenise(lexer::TokenList* ts, bool crlf, const std::string_view& fileContents, const util::FastInsertVector& lines, Location* pos, std::vector* importIndices) { size_t curLine = 0; size_t curOffset = 0; bool flag = true; size_t i = 0; do { // store it here so we can fiddle with it later, if we need to. auto tok_out = ts->getNextSlotAndIncrement(); auto type = lexer::getNextToken(lines, &curLine, &curOffset, fileContents, *pos, tok_out, crlf); // if we reached the end of file, do everybody a favour and insert a newline before the // EOF token. the lexer itself can't do this, because it can only operate on one token // at a time! if(type == lexer::TokenType::EndOfFile) { // here is the aforementioned fiddling. tok_out->type = lexer::TokenType::NewLine; tok_out->text = "\n"; // ok, now we can make another one. auto real_eof = ts->getNextSlotAndIncrement(); real_eof->loc = tok_out->loc; real_eof->type = lexer::TokenType::EndOfFile; } flag = (type != lexer::TokenType::EndOfFile); if(type == lexer::TokenType::Import) importIndices->push_back(i); else if(type == lexer::TokenType::Invalid) error(*pos, "invalid token"); i++; } while(flag); (*ts)[ts->size() - 1].loc.len = 0; } static void lex(FileInnards* innards, bool crlf, Location* pos) { lexer::TokenList& ts = innards->tokens; tokenise(&ts, crlf, innards->fileContents, innards->lines, pos, &innards->importIndices); innards->didLex = true; } FileInnards lexTokensFromString(const std::string& fakename, const std::string_view& fileContents) { // split into lines bool crlf = false; util::FastInsertVector rawlines; getRawLines(fileContents, &crlf, &rawlines); Location pos; FileInnards innards; { pos.fileID = getFileIDFromFilename(fakename); innards.fileContents = fileContents; innards.lines = std::move(rawlines); } lex(&innards, crlf, &pos); return innards; } static FileInnards& readFileIfNecessary(const std::string& fullPath) { // break early if we can { auto it = fileList.find(fullPath); if(it != fileList.end()) return it->second; } std::string_view fileContents = platform::readEntireFile(fullPath); // split into lines bool crlf = false; util::FastInsertVector rawlines; getRawLines(fileContents, &crlf, &rawlines); Location pos; FileInnards& innards = fileList[fullPath]; { pos.fileID = getFileIDFromFilename(fullPath); innards.fileContents = fileContents; innards.lines = std::move(rawlines); } lex(&innards, crlf, &pos); return innards; } FileInnards& getFileState(const std::string& name) { return readFileIfNecessary(name); } lexer::TokenList& getFileTokens(const std::string& fullPath) { return readFileIfNecessary(fullPath).tokens; } std::string getFileContents(const std::string& fullPath) { return std::string(readFileIfNecessary(fullPath).fileContents); } static std::vector fileNames { "null" }; static util::hash_map existingNames; void cachePreExistingFilename(const std::string& name) { fileNames.push_back(name); } const std::string& getFilenameFromID(size_t fileID) { iceAssert(fileID > 0 && fileID < fileNames.size()); return fileNames[fileID]; } size_t getFileIDFromFilename(const std::string& name) { if(existingNames.find(name) != existingNames.end()) { return existingNames[name]; } else { fileNames.push_back(name); existingNames[name] = fileNames.size() - 1; return fileNames.size() - 1; } } const util::FastInsertVector& getFileLines(size_t id) { return readFileIfNecessary(getFilenameFromID(id)).lines; } const std::vector& getImportTokenLocationsForFile(const std::string& filename) { return fileList[filename].importIndices; } std::string getPathFromFile(const std::string& path) { std::string ret; size_t sep = path.find_last_of("\\/"); if(sep != std::string::npos) ret = path.substr(0, sep); return ret; } std::string getFilenameFromPath(const std::string& path) { std::string ret; size_t sep = path.find_last_of("\\/"); if(sep != std::string::npos) ret = path.substr(sep + 1); return ret; } std::string getFullPathOfFile(const std::string& partial) { std::string full = platform::getFullPath(partial); if(full.empty()) error("nonexistent file %s", partial.c_str()); return full; } std::string removeExtensionFromFilename(const std::string& name) { auto i = name.find_last_of('.'); return name.substr(0, i); } } ================================================ FILE: source/frontend/import.cpp ================================================ // import.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include #include "errors.h" #include "frontend.h" #include "parser_internal.h" namespace frontend { // map from (imp, fullPath) -> resolvedPath static util::hash_map, std::string> importCache; // 'imp' is always a path std::string resolveImport(const std::string& imp, const Location& loc, const std::string& fullPath) { if(auto it = importCache.find({ imp, fullPath }); it != importCache.end()) return it->second; // std::string ext = ".flx"; // if(imp.size() > ext.size() && imp.find(".flx") == imp.size() - ext.size()) // ext = ""; std::string curpath = getPathFromFile(fullPath); std::string fullname = curpath + "/" + imp; if(fullname == fullPath) error(loc, "cannot import module from within itself"); std::string resolved; // a file here if(auto fname = platform::getFullPath(fullname); !fname.empty()) { resolved = fname; } else { std::string builtinlib = frontend::getParameter("sysroot") + "/" + frontend::getParameter("prefix") + "/lib/flaxlibs/" + imp; if(platform::checkFileExists(builtinlib)) { resolved = getFullPathOfFile(builtinlib); } else { SimpleError::make(loc, "no module or library at the path '%s' could be found", imp) ->append(BareError::make(MsgType::Note, "'%s' does not exist", fullname)) ->append(BareError::make(MsgType::Note, "'%s' does not exist", builtinlib)) ->postAndQuit(); } } importCache[{ imp, fullPath }] = resolved; return resolved; } } namespace parser { // TODO: do we want to combine this "pre-parsing" with the actual import parsing?? // note that the 'real' parse that we do (to make an AST) makes a useless AST, because we have no // use for imports after the files are collected. std::vector parseImports(const std::string& filename, const lexer::TokenList& tokens) { using Token = lexer::Token; using TT = lexer::TokenType; std::vector imports; // basically, this is how it goes: // only allow comments to occur before imports // all imports must happen before anything else in the file // comments can be interspersed between import statements, of course. for(size_t i = 0; i < tokens.size(); i++) { const Token& tok = tokens[i]; if(tok == TT::Import || ((tok == TT::Public || tok == TT::Private) && i + 1 < tokens.size() && tokens[i + 1] == TT::Import)) { bool pub = false; if(tok == TT::Public) i++, pub = true; else if(tok == TT::Private) i++, warn(tok.loc, "imports are private by default, 'private import' is redundant"); i++; std::string name; Location impLoc = tok.loc; std::vector impAs; if(tokens[i] == TT::StringLiteral) { name = tokens[i].str(); impLoc = impLoc.unionWith(tokens[i].loc); i++; } else if(tokens[i] == TT::Identifier) { auto [ loc, bits ] = parseIdentPath(tokens, &i); //* we concatanate the thing, using '/' as the path separator, and appending '.flx' to the end. name = zfu::join(bits, "/") + ".flx"; impLoc = impLoc.unionWith(loc); } else { expectedAfter(tokens[i].loc, "string literal or identifier path", "'import'", tokens[i].str()); } // check for 'import as foo' if(tokens[i] == TT::As) { i++; if(tokens[i] == TT::Identifier) impAs = parseIdentPath(tokens, &i).second; else expectedAfter(tokens[i - 1].loc, "identifier", "'import-as'", tokens[i - 1].str()); } if(tokens[i] != TT::NewLine && tokens[i] != TT::Semicolon && tokens[i] != TT::Comment) { error(tokens[i].loc, "expected newline or semicolon to terminate import statement, found '%s'", tokens[i].str()); } frontend::ImportThing it { name, impAs, pub, impLoc }; imports.push_back(it); // i++ handled by loop } else if(tok == TT::Export) { // skip until a newline. while(tokens[i] != TT::Comment && tokens[i] != TT::NewLine) i++; } else if(tok == TT::Comment || tok == TT::NewLine) { // skipped } else { // stop imports. break; } } return imports; } } ================================================ FILE: source/frontend/lexer.cpp ================================================ // lexer.cpp // Copyright (c) 2014 - 2015, zhiayang // Licensed under the Apache License Version 2.0. #include "lexer.h" #include "errors.h" #include "utf8rewind/include/utf8rewind/utf8rewind.h" using string_view = std::string_view; namespace lexer { static void skipWhitespace(string_view& line, Location& pos, size_t* offset) { size_t skip = 0; while(line.length() > skip && (line[skip] == '\t' || line[skip] == ' ')) { (line[skip] == ' ' ? pos.col++ : pos.col += TAB_WIDTH); skip++; } line.remove_prefix(skip); (*offset) += skip; } template static bool hasPrefix(const string_view& str, char const (&literal)[N]) { if(str.length() < N - 1) return false; for(size_t i = 0; i < N - 1; i++) if(str[i] != literal[i]) return false; return true; } template static bool compare(const string_view& str, char const (&literal)[N]) { if(str.length() != N - 1) return false; for(size_t i = 0; i < N - 1; i++) if(str[i] != literal[i]) return false; return true; } static TokenType prevType = TokenType::Invalid; static size_t prevID = 0; static bool shouldConsiderUnaryLiteral(string_view& stream, Location& pos) { // check the previous token bool should = (prevType != TokenType::Invalid && prevID == pos.fileID && ( prevType != TokenType::RParen && prevType != TokenType::RSquare && prevType != TokenType::Identifier && prevType != TokenType::Number && prevType != TokenType::Dollar && prevType != TokenType::StringLiteral )); if(!should) return false; // check if the current char is a + or - if(stream.length() == 0) return false; if(stream[0] != '+' && stream[0] != '-') return false; // check if there's only spaces between this and the number itself for(size_t i = 1; i < stream.length(); i++) { if(isdigit(stream[i])) return true; else if(stream[i] != ' ') return false; } return false; } static util::hash_map keywordMap; static void initKeywordMap() { if(keywordMap.size() > 0) return; keywordMap["as"] = TokenType::As; keywordMap["do"] = TokenType::Do; keywordMap["if"] = TokenType::If; keywordMap["is"] = TokenType::Is; keywordMap["let"] = TokenType::Val; keywordMap["var"] = TokenType::Var; keywordMap["for"] = TokenType::For; keywordMap["fn"] = TokenType::Func; keywordMap["else"] = TokenType::Else; keywordMap["true"] = TokenType::True; keywordMap["enum"] = TokenType::Enum; keywordMap["null"] = TokenType::Null; keywordMap["case"] = TokenType::Case; keywordMap["trait"] = TokenType::Trait; keywordMap["defer"] = TokenType::Defer; keywordMap["alloc"] = TokenType::Alloc; keywordMap["false"] = TokenType::False; keywordMap["while"] = TokenType::While; keywordMap["break"] = TokenType::Break; keywordMap["class"] = TokenType::Class; keywordMap["using"] = TokenType::Using; keywordMap["union"] = TokenType::Union; keywordMap["struct"] = TokenType::Struct; keywordMap["import"] = TokenType::Import; keywordMap["public"] = TokenType::Public; keywordMap["switch"] = TokenType::Switch; keywordMap["return"] = TokenType::Return; keywordMap["export"] = TokenType::Export; keywordMap["sizeof"] = TokenType::Sizeof; keywordMap["typeof"] = TokenType::Typeof; keywordMap["typeid"] = TokenType::Typeid; keywordMap["static"] = TokenType::Static; keywordMap["mut"] = TokenType::Mutable; keywordMap["free"] = TokenType::Dealloc; keywordMap["private"] = TokenType::Private; keywordMap["virtual"] = TokenType::Virtual; keywordMap["internal"] = TokenType::Internal; keywordMap["override"] = TokenType::Override; keywordMap["operator"] = TokenType::Operator; keywordMap["continue"] = TokenType::Continue; keywordMap["typealias"] = TokenType::TypeAlias; keywordMap["extension"] = TokenType::Extension; keywordMap["namespace"] = TokenType::Namespace; keywordMap["ffi"] = TokenType::ForeignFunc; } TokenType getNextToken(const util::FastInsertVector& lines, size_t* line, size_t* offset, const string_view& whole, Location& pos, Token* out, bool crlf) { bool flag = true; if(*line == lines.size()) { out->loc = pos; out->type = TokenType::EndOfFile; return TokenType::EndOfFile; } string_view stream = lines[*line].substr(*offset); skipWhitespace(stream, pos, offset); if(stream.empty() || stream[0] == 0) { out->loc = pos; out->type = TokenType::EndOfFile; return TokenType::EndOfFile; } size_t read = 0; size_t unicodeLength = 0; Token& tok = *out; tok.loc = pos; tok.type = TokenType::Invalid; // check compound symbols first. if(hasPrefix(stream, "//")) { tok.type = TokenType::Comment; // stream = stream.substr(0, 0); (*line)++; pos.line++; pos.col = 0; (*offset) = 0; // don't assign lines[line] = stream, since over here we've changed 'line' to be the next one. flag = false; tok.text = ""; } else if(hasPrefix(stream, "==")) { tok.type = TokenType::EqualsTo; tok.text = "=="; read = 2; } else if(hasPrefix(stream, ">=")) { tok.type = TokenType::GreaterEquals; tok.text = ">="; read = 2; } else if(hasPrefix(stream, "<=")) { tok.type = TokenType::LessThanEquals; tok.text = "<="; read = 2; } else if(hasPrefix(stream, "!=")) { tok.type = TokenType::NotEquals; tok.text = "!="; read = 2; } else if(hasPrefix(stream, "||")) { tok.type = TokenType::LogicalOr; tok.text = "||"; read = 2; } else if(hasPrefix(stream, "&&")) { tok.type = TokenType::LogicalAnd; tok.text = "&&"; read = 2; } else if(hasPrefix(stream, "<-")) { tok.type = TokenType::LeftArrow; tok.text = "<-"; read = 2; } else if(hasPrefix(stream, "->")) { tok.type = TokenType::RightArrow; tok.text = "->"; read = 2; } else if(hasPrefix(stream, "<=")) { tok.type = TokenType::FatLeftArrow; tok.text = "<="; read = 2; } else if(hasPrefix(stream, "=>")) { tok.type = TokenType::FatRightArrow; tok.text = "=>"; read = 2; } else if(hasPrefix(stream, "++")) { tok.type = TokenType::DoublePlus; tok.text = "++"; read = 2; } else if(hasPrefix(stream, "--")) { tok.type = TokenType::DoubleMinus; tok.text = "--"; read = 2; } else if(hasPrefix(stream, "+=")) { tok.type = TokenType::PlusEq; tok.text = "+="; read = 2; } else if(hasPrefix(stream, "-=")) { tok.type = TokenType::MinusEq; tok.text = "-="; read = 2; } else if(hasPrefix(stream, "*=")) { tok.type = TokenType::MultiplyEq; tok.text = "*="; read = 2; } else if(hasPrefix(stream, "/=")) { tok.type = TokenType::DivideEq; tok.text = "/="; read = 2; } else if(hasPrefix(stream, "%=")) { tok.type = TokenType::ModEq; tok.text = "%="; read = 2; } else if(hasPrefix(stream, "&=")) { tok.type = TokenType::AmpersandEq; tok.text = "&="; read = 2; } else if(hasPrefix(stream, "|=")) { tok.type = TokenType::PipeEq; tok.text = "|="; read = 2; } else if(hasPrefix(stream, "^=")) { tok.type = TokenType::CaretEq; tok.text = "^="; read = 2; } else if(hasPrefix(stream, "::")) { tok.type = TokenType::DoubleColon; tok.text = "::"; read = 2; } else if(hasPrefix(stream, "...")) { tok.type = TokenType::Ellipsis; tok.text = "..."; read = 3; } else if(hasPrefix(stream, "..<")) { tok.type = TokenType::HalfOpenEllipsis; tok.text = "..<"; read = 3; } else if(hasPrefix(stream, "/*")) { int currentNest = 1; // support nested, so basically we have to loop until we find either a /* or a */ stream.remove_prefix(2); (*offset) += 2; pos.col += 2; Location opening = pos; Location curpos = pos; size_t k = 0; while(currentNest > 0) { // we can do this, because we know the closing token (*/) is 2 chars long // so if we have 1 char left, gg. if(k + 1 == stream.size() || stream[k] == '\n') { if(*line + 1 == lines.size()) error(opening, "expected closing */ (reached EOF), for block comment started here:"); // else, get the next line. // also note: if we're in this loop, we're inside a block comment. // since the ending token cannot be split across lines, we know that this last char // must also be part of the comment. hence, just skip over it. k = 0; curpos.line++; curpos.col = 0; (*offset) = 0; (*line)++; stream = lines[*line]; continue; } if(stream[k] == '/' && stream[k + 1] == '*') currentNest++, k++, curpos.col++, opening = curpos; else if(stream[k] == '*' && stream[k + 1] == '/') currentNest--, k++, curpos.col++; k++; curpos.col++; } if(currentNest != 0) error(opening, "expected closing */ (reached EOF), for block comment started here:"); pos = curpos; // don't actually store the text, because it's pointless and memory-wasting // tok.text = "/* I used to be a comment like you, until I took a memory-leak to the knee. */"; tok.type = TokenType::Comment; tok.text = ""; read = k; } else if(hasPrefix(stream, "*/")) { error(tok.loc, "unexpected '*/'"); } // attrs else if(hasPrefix(stream, "@nomangle")) { tok.type = TokenType::Attr_NoMangle; tok.text = "@nomangle"; read = 9; } else if(hasPrefix(stream, "@entry")) { tok.type = TokenType::Attr_EntryFn; tok.text = "@entry"; read = 6; } else if(hasPrefix(stream, "@packed")) { tok.type = TokenType::Attr_Packed; tok.text = "@packed"; read = 7; } else if(hasPrefix(stream, "@raw")) { tok.type = TokenType::Attr_Raw; tok.text = "@raw"; read = 4; } else if(hasPrefix(stream, "@operator")) { tok.type = TokenType::Attr_Operator; tok.text = "@operator"; read = 9; } else if(hasPrefix(stream, "@platform")) { tok.type = TokenType::Attr_Platform; tok.text = "@platform"; read = 9; } // directives else if(hasPrefix(stream, "#if")) { tok.type = TokenType::Directive_If; tok.text = "#if"; read = 3; } else if(hasPrefix(stream, "#run")) { tok.type = TokenType::Directive_Run; tok.text = "#run"; read = 4; } // unicode stuff else if(hasPrefix(stream, "ƒ")) { tok.type = TokenType::Func; read = std::string("ƒ").length(); tok.text = "ƒ"; unicodeLength = 1; } else if(hasPrefix(stream, "fi")) { tok.type = TokenType::ForeignFunc; read = std::string("fi").length(); tok.text = "fi"; unicodeLength = 1; } else if(hasPrefix(stream, "÷")) { tok.type = TokenType::Divide; read = std::string("÷").length(); tok.text = "÷"; unicodeLength = 1; } else if(hasPrefix(stream, "≠")) { tok.type = TokenType::NotEquals; read = std::string("≠").length(); tok.text = "≠"; unicodeLength = 1; } else if(hasPrefix(stream, "≤")) { tok.type = TokenType::LessThanEquals; read = std::string("≤").length(); tok.text = "≤"; unicodeLength = 1; } else if(hasPrefix(stream, "≥")) { tok.type = TokenType::GreaterEquals; read = std::string("≥").length(); tok.text = "≥"; unicodeLength = 1; } else if(hasPrefix(stream, "'") && stream.size() > 2) { tok.type = TokenType::CharacterLiteral; if(stream[1] == '\\') { switch(stream[2]) { case 'n': tok.text = "\n"; break; case 'b': tok.text = "\b"; break; case 'a': tok.text = "\a"; break; case 'r': tok.text = "\r"; break; case 't': tok.text = "\t"; break; case '\'': tok.text = "'"; break; case '\\': tok.text = "\\"; break; default: error(pos, "invalid escape sequence ('\\%c') in character literal", stream[2]); } read = 4; } else { tok.text = stream.substr(1, 1); read = 3; } if(stream[read - 1] != '\'') error(pos, "expected closing '"); } // note some special-casing is needed to differentiate between unary +/- and binary +/- // cases where we want binary: // ...) + 3 | ...] + 3 | ident + 3 | number + 3 | string + 3 // so in every other case we want unary +/-. // note: a sane implementation would just return false if isdigit() was passed something weird, like a negative number // (because we tried to dissect a UTF-8 codepoint). so we just check if it's ascii first, which would solve the issue. else if((!stream.empty() && ((isascii(stream[0]) && isdigit(stream[0])) || shouldConsiderUnaryLiteral(stream, pos))) /* handle cases like '+ 3' or '- 14' (ie. space between sign and number) */ && ((isascii(stream[0]) && isdigit(stream[0]) ? true : false) || (stream.size() > 1 && isascii(stream[1]) && isdigit(stream[1])))) { // copy it. auto tmp = stream; if(tmp.find('-') == 0 || tmp.find('+') == 0) tmp.remove_prefix(1); int base = 10; if(tmp.find("0x") == 0 || tmp.find("0X") == 0) base = 16, tmp.remove_prefix(2); else if(tmp.find("0b") == 0 || tmp.find("0B") == 0) base = 2, tmp.remove_prefix(2); // find that shit auto end = std::find_if_not(tmp.begin(), tmp.end(), [base](const char& c) -> bool { if(base == 10) return isdigit(c); if(base == 16) return isdigit(c) || (toupper(c) >= 'A' && toupper(c) <= 'F'); else return (c == '0' || c == '1'); }); tmp.remove_prefix((end - tmp.begin())); // check if we have 'e' or 'E' bool hadExp = false; if(tmp.size() > 0 && (tmp[0] == 'e' || tmp[0] == 'E')) { if(base != 10) error("exponential form is supported with neither hexadecimal nor binary literals"); // find that shit auto next = std::find_if_not(tmp.begin() + 1, tmp.end(), isdigit); // this does the 'e' as well. tmp.remove_prefix(next - tmp.begin()); hadExp = true; } size_t didRead = stream.size() - tmp.size(); auto post = stream.substr(didRead); if(!post.empty() && post[0] == '.') { if(base != 10) error("invalid floating point literal; only valid in base 10"); else if(hadExp) error("invalid floating point literal; decimal point cannot occur after the exponent ('e' or 'E')."); // if the previous token was a '.' as well, then we're doing some tuple access // eg. x.0.1 (we would be at '0', having a period both ahead and behind us) // if the next token is not a number, then same thing, eg. // x.0.z, where the first tuple element of 'x' is a struct or something. // so -- lex a floating point *iff* the previous token was not '.', and the next token is a digit. if(prevType != TokenType::Period && post.size() > 1 && isdigit(post[1])) { // yes, parse a floating point post.remove_prefix(1), didRead++; while(post.size() > 0 && isdigit(post.front())) post.remove_prefix(1), didRead++; // ok. } else { // no, just return the integer token. // (which we do below, so just do nothing here) } } tok.text = stream.substr(0, didRead); tok.type = TokenType::Number; tok.loc.len = didRead; read = didRead; } else if(!stream.empty() && (stream[0] == '_' || utf8iscategory(stream.data(), stream.size(), UTF8_CATEGORY_LETTER) > 0)) { // get as many letters as possible first size_t identLength = utf8iscategory(stream.data(), stream.size(), UTF8_CATEGORY_LETTER | UTF8_CATEGORY_PUNCTUATION_CONNECTOR | UTF8_CATEGORY_NUMBER); read = identLength; tok.text = stream.substr(0, identLength); initKeywordMap(); if(auto it = keywordMap.find(tok.text); it != keywordMap.end()) tok.type = it->second; else tok.type = TokenType::Identifier; // again, assume that one codepoint is 1 character wide? // note: we convert to std::string because I believe utf8len expects null-term strings, but // tok.text is a string_view. unicodeLength = utf8len(std::string(tok.text).c_str()); } else if(!stream.empty() && stream[0] == '"') { // string literal // because we want to avoid using std::string (ie. copying) in the lexer (Token), we must send the string over verbatim. // store the starting position size_t start = (stream.data() - whole.data() + 1); // opening " pos.col++; size_t i = 1; size_t didRead = 0; for(; stream[i] != '"'; i++) { if(stream[i] == '\\') { if(i + 1 == stream.size()) { error(pos, "unexpected end of input"); } else if(stream[i + 1] == '"') { // add the quote and the backslash, and skip it. didRead += 2; pos.col += 2; i++; } // breaking string over two lines else if(stream[i + 1] == '\n') { // skip it, then move to the next line pos.line++; pos.col = 0; (*line)++; if(*line == lines.size()) error(pos, "unexpected end of input"); i = 0; // just a fudge factor gotten from empirical evidence // 3 extra holds for multiple lines, so all is well. didRead += 3; stream = lines[*line]; (*offset) = 0; } else if(stream[i + 1] == '\\') { i++; didRead += 2; pos.col += 2; } else { // just put the backslash in. // and don't skip the next one. didRead++; pos.col++; } continue; } didRead++; pos.col++; if(i == stream.size() - 1 || stream[i] == '\n') { error(pos, "expected closing '\"'"); } } // closing " pos.col++; tok.type = TokenType::StringLiteral; tok.text = whole.substr(start, didRead); tok.loc.len = 2 + didRead; stream = stream.substr(i + 1); (*offset) += i + 1; read = 0; flag = false; } else if(crlf && hasPrefix(stream, "\r\n")) { read = 2; flag = false; tok.type = TokenType::NewLine; tok.text = "\n"; } else if(!stream.empty()) { if(isascii(stream[0])) { // check the first char switch(stream[0]) { // for single-char things case '\n': tok.type = TokenType::NewLine; break; case '{': tok.type = TokenType::LBrace; break; case '}': tok.type = TokenType::RBrace; break; case '(': tok.type = TokenType::LParen; break; case ')': tok.type = TokenType::RParen; break; case '[': tok.type = TokenType::LSquare; break; case ']': tok.type = TokenType::RSquare; break; case '<': tok.type = TokenType::LAngle; break; case '>': tok.type = TokenType::RAngle; break; case '+': tok.type = TokenType::Plus; break; case '-': tok.type = TokenType::Minus; break; case '*': tok.type = TokenType::Asterisk; break; case '/': tok.type = TokenType::Divide; break; case '\'': tok.type = TokenType::SQuote; break; case '.': tok.type = TokenType::Period; break; case ',': tok.type = TokenType::Comma; break; case ':': tok.type = TokenType::Colon; break; case '=': tok.type = TokenType::Equal; break; case '?': tok.type = TokenType::Question; break; case '!': tok.type = TokenType::Exclamation; break; case ';': tok.type = TokenType::Semicolon; break; case '&': tok.type = TokenType::Ampersand; break; case '%': tok.type = TokenType::Percent; break; case '|': tok.type = TokenType::Pipe; break; case '@': tok.type = TokenType::At; break; case '#': tok.type = TokenType::Pound; break; case '~': tok.type = TokenType::Tilde; break; case '^': tok.type = TokenType::Caret; break; case '$': tok.type = TokenType::Dollar; break; default: error(tok.loc, "unknown token '%c'", stream[0]); } tok.text = stream.substr(0, 1); // tok.loc.col += 1; read = 1; } else if(utf8iscategory(stream.data(), stream.size(), UTF8_CATEGORY_SYMBOL_MATH | UTF8_CATEGORY_PUNCTUATION_OTHER) > 0) { read = utf8iscategory(stream.data(), stream.size(), UTF8_CATEGORY_SYMBOL_MATH | UTF8_CATEGORY_PUNCTUATION_OTHER); tok.text = stream.substr(0, read); tok.type = TokenType::UnicodeSymbol; // assume that everything is one character wide only! unicodeLength = 1; } else { // one char wide, at least. not in bytes. auto l = tok.loc; l.len = 1; // get the number of bytes of the next codepoint, by seeking +1 and subtracting the pointer. auto cplen = utf8seek(stream.data(), stream.size(), stream.data(), 1, SEEK_SET) - stream.data(); error(l, "unknown token '%s'", stream.substr(0, cplen)); } } stream.remove_prefix(read); if(flag) (*offset) += read; if(tok.type != TokenType::NewLine) { if(read > 0) { // note(debatable): put the actual "position" in the front of the token pos.col += (unicodeLength > 0 ? unicodeLength : read); // special handling -- things like ƒ, ≤ etc. are one character wide, but can be several *bytes* long. pos.len = (unicodeLength > 0 ? unicodeLength : read); tok.loc.len = (unicodeLength > 0 ? unicodeLength : read); } } else { pos.col = 0; pos.line++; (*line)++; (*offset) = 0; } prevType = tok.type; prevID = tok.loc.fileID; return prevType; } } ================================================ FILE: source/frontend/parser/controlflow.cpp ================================================ // controlflow.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "parser_internal.h" #include "memorypool.h" namespace parser { using TT = lexer::TokenType; using namespace ast; PResult parseIfStmt(State& st) { using Case = IfStmt::Case; auto tok_if = st.eat(); iceAssert(tok_if == TT::If || tok_if == TT::Directive_If); bool isStaticIf = tok_if == TT::Directive_If; // of this form: // if(var x = 30; var k = 30; x == k) { ... } else if(cond) { ... } // braces are compulsory // parentheses around the condition are not Block* elseCase = 0; std::vector cases; cases.push_back(Case()); // first one { // ok -- the first one we must do manually. // probably not, but i'm lazy. while(st.front() == TT::Val || st.front() == TT::Var) { cases.back().inits.push_back(parseVariable(st)); st.skipWS(); if(st.front() != TT::Semicolon) expectedAfter(st, "semicolon ';'", "if-variable-initialisation", st.front().str()); st.eat(); } // ok, we finished doing the variables. cases.back().cond = parseExpr(st); if(auto x = parseBracedBlock(st); x.isError()) return PResult::copyError(x); else cases.back().body = x.val(); } // ok, do the else-if chain while(st.frontAfterWS() == TT::Else) { st.eat(); if(st.front() == TT::If) { Case c; // ok, it's an else-if. st.eat(); while(st.front() == TT::Val || st.front() == TT::Var) { c.inits.push_back(parseVariable(st)); st.skipWS(); if(st.front() != TT::Semicolon) expectedAfter(st, "semicolon ';'", "if-variable-initialisation", st.front().str()); st.eat(); } c.cond = parseExpr(st); if(auto x = parseBracedBlock(st); x.isError()) return PResult::copyError(x); else c.body = x.val(); cases.push_back(c); } else if(st.frontAfterWS() == TT::LBrace || st.frontAfterWS() == TT::FatRightArrow) { // ok, parse an else elseCase = parseBracedBlock(st).val(); break; } else { // um. expectedAfter(st, "'if' or '{'", "'else'", st.frontAfterWS().str()); } } if(isStaticIf) { // compile-time if auto ret = util::pool(tok_if.loc); ret->cases = cases; ret->elseCase = elseCase; for(auto& c : ret->cases) c.body->doNotPushNewScope = true; if(ret->elseCase) ret->elseCase->doNotPushNewScope = true; return ret; } else { // normal runtime if auto ret = util::pool(tok_if.loc); ret->cases = cases; ret->elseCase = elseCase; return ret; } } ReturnStmt* parseReturn(State& st) { iceAssert(st.front() == TT::Return); auto ret = util::pool(st.loc()); st.eat(); // check what's the next thing. problem: return has an *optional* value // solution: the value must not be separated by any whitespace or comment tokens if(st.front() != TT::Comment && st.front() != TT::NewLine && st.front() != TT::RBrace && st.front() != TT::EndOfFile) { ret->value = parseExpr(st); } else { // do nothing } return ret; } Stmt* parseForLoop(State& st) { iceAssert(st.front() == TT::For); st.eat(); if(!zfu::match(st.front(), TT::Identifier, TT::LParen)) expectedAfter(st.loc(), "'(' or identifier", "'for'", st.front().str()); auto ret = util::pool(st.ploc()); if(st.front() == TT::LParen) { ret->bindings = parseTupleDecomp(st); } else if(st.front() == TT::Ampersand || st.front() == TT::Identifier) { if(st.front() == TT::Ampersand) ret->bindings.ref = true, st.pop(); ret->bindings.loc = st.loc(); ret->bindings.name = st.eat().str(); } else { expectedAfter(st.loc(), "one or more variable bindings", "'for'", st.front().str()); } // check for the comma for the index variable if(st.front() == TT::Comma) { st.pop(); if(st.front() != TT::Identifier) expectedAfter(st.loc(), "identifier for index binding", "',' in for loop", st.front().str()); else if(st.front().str() == "_") error("redundant use of '_' in binding for index variable in for loop; omit the binding entirely to ignore the index variable"); ret->indexVar = st.eat().str(); } if(st.front() != TT::Identifier || st.front().str() != "in") expected(st.loc(), "'in' in for-loop", st.front().str()); st.eat(); // get the array. ret->array = parseExpr(st); st.skipWS(); ret->body = parseBracedBlock(st).val(); return ret; } PResult parseWhileLoop(State& st) { // 1. do { } -- body = block, cond = 0, doVariant = true // 2. while x { } -- body = block, cond = x, doVariant = false // 3. do { } while x -- body = block, cond = x, doVariant = true auto loc = st.loc(); Expr* cond = 0; Block* body = 0; bool isdo = false; iceAssert(st.front() == TT::While || st.front() == TT::Do); if(st.front() == TT::While) { st.eat(); cond = parseExpr(st); st.skipWS(); auto res = parseBracedBlock(st); if(res.isError()) return PResult::copyError(res); body = res.val(); } else { isdo = true; st.eat(); auto res = parseBracedBlock(st); if(res.isError()) return PResult::copyError(res); body = res.val(); if(st.front() == TT::While) { st.eat(); // do a check for stupid "do { } while { }" if(st.frontAfterWS() == TT::LBrace) expected(st.frontAfterWS().loc, "conditional expression after while", st.frontAfterWS().str()); cond = parseExpr(st); } } auto ret = util::pool(loc); ret->isDoVariant = isdo; ret->body = body; ret->cond = cond; return ret; } Stmt* parseBreak(State& st) { iceAssert(st.front() == TT::Break); return util::pool(st.eat().loc); } Stmt* parseContinue(State& st) { iceAssert(st.front() == TT::Continue); return util::pool(st.eat().loc); } } ================================================ FILE: source/frontend/parser/expr.cpp ================================================ // expr.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "parser.h" #include "parser_internal.h" #include "memorypool.h" using namespace ast; using namespace lexer; namespace parser { using TT = lexer::TokenType; PResult parseStmtWithAccessSpec(State& st) { iceAssert(st.front() == TT::Public || st.front() == TT::Private || st.front() == TT::Internal); auto vis = VisibilityLevel::Invalid; switch(st.front()) { case TT::Public: vis = VisibilityLevel::Public; break; case TT::Private: vis = VisibilityLevel::Private; break; case TT::Internal: vis = VisibilityLevel::Internal; break; default: iceAssert(0); } st.pop(); return parseStmt(st, /* allowExprs: */ false).mutate([&](auto stmt) -> void { if(auto fd = dcast(FuncDefn, stmt)) fd->visibility = vis; else if(auto ffd = dcast(ForeignFuncDefn, stmt)) ffd->visibility = vis; else if(auto vd = dcast(VarDefn, stmt)) vd->visibility = vis; else if(auto td = dcast(TypeDefn, stmt)) td->visibility = vis; else error(st, "access specifier cannot be applied to this statement"); }); } PResult parseStmt(State& st, bool allowExprs) { if(!st.hasTokens()) return PResult::insufficientTokensError(); st.skipWS(); std::function (bool, bool, bool)> checkMethodModifiers = [&st, &checkMethodModifiers] (bool mut, bool virt, bool ovrd) -> PResult { if(st.front() == TT::Mutable) { if(mut) error(st.loc(), "duplicate 'mut' modifier"); st.eat(); return checkMethodModifiers(true, virt, ovrd); } else if(st.front() == TT::Virtual) { if(virt) error(st.loc(), "duplicate 'virtual' modifier"); if(ovrd) error(st.loc(), "'override' implies 'virtual', just use 'override'"); st.eat(); //* but virtual does not imply override return checkMethodModifiers(mut, true, ovrd); } else if(st.front() == TT::Override) { if(ovrd) error(st.loc(), "duplicate 'override' modifier"); if(virt) error(st.loc(), "'override' implies 'virtual', just use 'override'"); st.eat(); //* override implies virtual return checkMethodModifiers(mut, true, true); } else { return PResult(parseFunction(st)).mutate([&](auto ret) -> void { ret->isVirtual = virt; ret->isOverride = ovrd; ret->isMutating = mut; }); } }; auto tok = st.front(); if(tok != TT::EndOfFile) { auto attrs = parseAttributes(st); auto enforceAttrs = [&attrs](const PResult& ret, const AttribSet& allowed = AttribSet::of(attr::NONE)) -> PResult { using namespace attr; return ret.map([&allowed, &attrs](auto ret) -> Stmt* { // there's probably a better way to do this, but bleugh if((attrs.flags & RAW) && !(allowed.flags & RAW)) error(ret, "unsupported attribute '@raw' on %s", ret->readableName); if((attrs.flags & NO_MANGLE) && !(allowed.flags & NO_MANGLE)) error(ret, "unsupported attribute '@nomangle' on %s", ret->readableName); if((attrs.flags & FN_ENTRYPOINT) && !(allowed.flags & FN_ENTRYPOINT)) error(ret, "unsupported attribute '@entry' on %s", ret->readableName); if((attrs.flags & PACKED) && !(allowed.flags & PACKED)) error(ret, "unsupported attribute '@packed' on %s", ret->readableName); // here let's check the arguments and stuff for default attributes. // note: due to poor API design on my part, if there is no attribute with that name then ::get() // returns an empty UA, which has a blank name -- so we check that instead. if(auto ua = attrs.get("compiler_support"); !ua.name.empty() && ua.args.size() != 1) error(ret, "@compiler_support requires exactly one argument"); // actually that's it ret->attrs = attrs; return ret; }); }; // handle the things that are OK to appear anywhere first: tok = st.front(); switch(tok.type) { case TT::Var: [[fallthrough]]; case TT::Val: return enforceAttrs(parseVariable(st), AttribSet::of(attr::NO_MANGLE)); case TT::Func: return enforceAttrs(parseFunction(st), AttribSet::of(attr::NO_MANGLE | attr::FN_ENTRYPOINT)); case TT::ForeignFunc: return enforceAttrs(parseForeignFunction(st)); case TT::Public: [[fallthrough]]; case TT::Private: [[fallthrough]]; case TT::Internal: return enforceAttrs(parseStmtWithAccessSpec(st)); case TT::Directive_If: return enforceAttrs(parseIfStmt(st)); case TT::Directive_Run: return enforceAttrs(parseRunDirective(st)); case TT::Union: return enforceAttrs(parseUnion(st, attrs.has(attr::RAW), /* nameless: */ false), AttribSet::of(attr::RAW)); case TT::Struct: return enforceAttrs(parseStruct(st, /* nameless: */ false), AttribSet::of(attr::PACKED)); case TT::Class: return enforceAttrs(parseClass(st)); case TT::Enum: return enforceAttrs(parseEnum(st)); case TT::Trait: return enforceAttrs(parseTrait(st)); case TT::Static: return enforceAttrs(parseStaticDecl(st)); case TT::Operator: return enforceAttrs(parseOperatorOverload(st)); case TT::Using: return enforceAttrs(parseUsingStmt(st)); case TT::Mutable: [[fallthrough]]; case TT::Virtual: [[fallthrough]]; case TT::Override: return enforceAttrs(checkMethodModifiers(false, false, false), AttribSet::of(attr::NO_MANGLE)); case TT::Extension: [[fallthrough]]; case TT::TypeAlias: error(st, "notsup"); case TT::Else: error(st, "cannot have 'else' without preceeding 'if'"); case TT::Namespace: error(st, "namespaces can only be defined at the top-level scope"); case TT::Import: error(st, "all imports must happen at the top-level scope"); case TT::Attr_Operator: error(st, "all operator declarations must happen at the top-level scope"); case TT::Export: error(st, "export declaration must be the first non-comment line in the file"); default: // do nothing. break; } // if we got here, then it wasn't any of those things. // we store it first, so we can give better error messages (after knowing what it is) // in the event that it wasn't allowed at top-level. auto ret = [&st, &tok, &allowExprs]() -> PResult { switch(tok.type) { case TT::Return: return parseReturn(st); case TT::If: return parseIfStmt(st); case TT::Else: error(st, "cannot have 'else' without preceeding 'if'"); case TT::Do: [[fallthrough]]; case TT::While: return parseWhileLoop(st); case TT::For: return parseForLoop(st); case TT::Break: return parseBreak(st); case TT::Continue: return parseContinue(st); case TT::Dealloc: return parseDealloc(st); case TT::Defer: return parseDefer(st); default: { if(st.isInStructBody() && tok.type == TT::Identifier) { if(tok.str() == "init") { return parseInitFunction(st); } else if(tok.str() == "deinit") { return parseDeinitFunction(st); } else if(tok.str() == "copy" || tok.str() == "move") { return parseCopyOrMoveInitFunction(st, tok.str()); } } // we want to error on invalid tokens first. so, we parse the expression regardless, // then if they're not allowed we error. return PResult(parseExpr(st)).mutate([&](auto expr) -> void { if(!allowExprs) error(expr, "expressions are not allowed at the top-level"); }); } } }(); return ret.mutate([&](auto ret) { if(!allowExprs && !st.isInFunctionBody() && !st.isInStructBody()) error(ret, "%s is not allowed at the top-level", ret->readableName); }); } return PResult::insufficientTokensError(); } static bool isRightAssociative(TT tt) { return false; } static bool isPostfixUnaryOperator(State& st, const Token& tk) { bool res = (tk == TT::LParen) || (tk == TT::LSquare) || (tk == TT::DoublePlus) || (tk == TT::DoubleMinus); if(auto it = st.postfixOps.find(tk.str()); !res && it != st.postfixOps.end()) { iceAssert(it->second.kind == CustomOperatorDecl::Kind::Postfix); res = true; } return res; } static int unaryPrecedence(const std::string& op) { if(op == "!" || op == "+" || op == "-" || op == "~" || op == "*" || op == "&" || op == "...") return 950; return -1; } static int tok_precedence(State& st, TokenType t) { switch(t) { /* ! ACHTUNG ! * DOCUMENT THIS SOMEWHERE PROPERLY!!! * due to how we handle identifiers and scope paths (foo::bar), function calls must have higher precedence than scope resolution. this might seem counter-intuitive (i should be resolving the complete identifier first, then calling it with ()! why would it be any other way???), this is a sad fact of how the typechecker works. as it stands, identifiers are units; paths consist of multiple identifiers in a DotOp with the :: operator, which is left-associative. so for something like foo::bar::qux, it's ((foo)::(bar))::qux. to resolve a function call, eg. foo::bar::qux(), the DotOp is laid out as [foo::bar]::[qux()] (with [] for grouping), instead of the 'intuitive' [[foo::bar]::qux](). the reason for this design was the original rewrite goal of not relying on string manipulation in the compiler; having identifiers contain :: would have been counter to that goal. (note: currently we are forced to manipulate ::s in the pts->fir type converter!!) the current typechecker will thus first find a namespace 'foo', and within that a namespace 'bar', and within that a function 'qux'. this is opposed to finding a namespace 'foo', then 'bar', then an identifier 'qux', and leaving that to be resolved later. also, another potential issue is how we deal with references to functions (ie. function pointers). our resolver for ExprCall is strictly less advanced than that for a normal FunctionCall (for reasons i can't reCALL (lmao)), so we would prefer to return a FuncCall rather than an ExprCall. this model could be re-architected without a *major* rewrite, but it would be a non-trivial task and a considerable amount of work and debugging. for reference: 1. make Idents be able to refer to entire paths; just a datastructure change 2. make :: have higher precedence than (), to take advantage of (1) 3. parse ExprCall and FuncCall identically -- they should both just be a NewCall, with an Expr as the callee 4. in typechecking a NewCall, just call ->typecheck() on the LHS; the current implementation of Ident::typecheck returns an sst::VarRef, which has an sst::VarDefn field which we can use. 4a. if the Defn was a VarDefn, they cannot overload, and we can just do what we currently do for ExprCall. if it was a function defn, then things get more complicated. 5. the Defn was a FuncDefn. currently Ident cannot return more than one Defn in the event of ambiguous results (eg. when overloading!), which means we are unable to properly do overload resolution! (duh) we need to make a mechanism for Ident to return a list of Defns. potential solution (A): make an sst::AmbiguousDefn struct that itself holds a list of Defns. the VarRef returned by Ident would then return that in the ->def field. this would only happen when the target is function; i presume we have existing mechanisms to detect invalid "overload" scenarios. back to (4), we should in theory be able to resolve functions from a list of defns. the problem with this is that while it might seem like a simple 5.5-step plan, a lot of the supporting resolver functions need to change, and effort is better spent elsewhere tbh for now we just stick to parsing () at higher precedence than ::. */ case TT::LParen: return 9001; // very funny case TT::DoubleColon: return 5000; case TT::Period: return 1500; case TT::LSquare: return 1000; // unary ! // unary +/- // bitwise ~ // unary & // unary * // unary ... (splat) // ^^ all have 950. case TT::As: [[fallthrough]]; case TT::Is: return 900; case TT::DoublePlus: [[fallthrough]]; case TT::DoubleMinus: return 850; case TT::Asterisk: [[fallthrough]]; case TT::Divide: [[fallthrough]]; case TT::Percent: return 800; case TT::Plus: [[fallthrough]]; case TT::Minus: return 750; // << and >> // precedence = 700 case TT::Ampersand: return 650; case TT::Caret: return 600; case TT::Pipe: return 550; case TT::LAngle: [[fallthrough]]; case TT::RAngle: [[fallthrough]]; case TT::LessThanEquals:[[fallthrough]]; case TT::GreaterEquals: [[fallthrough]]; case TT::EqualsTo: [[fallthrough]]; case TT::NotEquals: return 500; case TT::Ellipsis: [[fallthrough]]; case TT::HalfOpenEllipsis: return 475; case TT::LogicalAnd: return 400; case TT::LogicalOr: return 350; case TT::Equal: [[fallthrough]]; case TT::PlusEq: [[fallthrough]]; case TT::MinusEq: [[fallthrough]]; case TT::MultiplyEq: [[fallthrough]]; case TT::DivideEq: [[fallthrough]]; case TT::ModEq: [[fallthrough]]; case TT::AmpersandEq: [[fallthrough]]; case TT::PipeEq: [[fallthrough]]; case TT::CaretEq: return 100; default: if(auto it = st.binaryOps.find(st.front().str()); it != st.binaryOps.end()) return it->second.precedence; else if(it = st.postfixOps.find(st.front().str()); it != st.postfixOps.end()) return it->second.precedence; return -1; } } static int precedence(State& st) { if(st.remaining() > 1 && (st.front() == TT::LAngle || st.front() == TT::RAngle)) { // check if the next one matches. if(st.front().type == TT::LAngle && st.lookahead(1).type == TT::LAngle) return 650; else if(st.front().type == TT::RAngle && st.lookahead(1).type == TT::RAngle) return 650; else if(st.front().type == TT::LAngle && st.lookahead(1).type == TT::LessThanEquals) return 100; else if(st.front().type == TT::RAngle && st.lookahead(1).type == TT::GreaterEquals) return 100; } return tok_precedence(st, st.front()); } static Expr* parseUnary(State& st); static Expr* parsePrimary(State& st); static Expr* parsePostfixUnary(State& st, Expr* lhs, Token op); static Expr* parseRhs(State& st, Expr* lhs, int prio) { if(!st.hasTokens() || st.front() == TT::EndOfFile) return lhs; while(true) { int prec = precedence(st); if((prec < prio && !isRightAssociative(st.front())) || (st.front() == TT::As && st.isParsingUsing())) return lhs; // we don't really need to check, because if it's botched we'll have returned due to -1 < everything if(auto tok_op = st.front(); isPostfixUnaryOperator(st, tok_op)) { st.eat(); lhs = parsePostfixUnary(st, dcast(Expr, lhs), tok_op); continue; } auto loc = st.loc(); auto op = parseOperatorTokens(st); if(op.empty()) error(loc, "invalid operator '%s'", st.prev().str()); Expr* rhs = 0; if(op == Operator::TypeCast) { if(st.front() == TT::Mutable || (st.front() == TT::Exclamation && st.lookahead(1) == TT::Mutable)) { if(st.front() == TT::Mutable) { st.pop(); rhs = util::pool(loc, true); } else { st.pop(); st.pop(); rhs = util::pool(loc, false); } } else { // rhs = util::pool(loc, parseType(st)); rhs = parseExpr(st); } } else if(op == Operator::TypeIs) { // rhs = util::pool(loc, parseType(st)); rhs = parseExpr(st); } else { rhs = parseUnary(st); } int next = precedence(st); if(next > prec || isRightAssociative(st.front())) rhs = parseRhs(st, rhs, prec + 1); if(op == "." || op == "::") { loc.col = lhs->loc.col; loc.len = rhs->loc.col + rhs->loc.len - lhs->loc.col; auto dot = util::pool(loc, dcast(Expr, lhs), rhs); dot->isStatic = (op == "::"); lhs = dot; } else if(op == "..." || op == "..<") { Expr* start = lhs; iceAssert(start); // current token now starts the ending expression (ie. '...' or '..<' are no longer in the token stream) Expr* end = rhs; Expr* step = 0; // check if we got a step. if(st.front() == TT::Identifier && st.front().text == "step") { st.eat(); step = parseExpr(st); } // ok auto ret = util::pool(loc); ret->start = start; ret->end = end; ret->halfOpen = (op == "..<"); ret->step = step; lhs = ret; } else if(Operator::isAssignment(op)) { auto newlhs = util::pool(loc); newlhs->left = dcast(Expr, lhs); newlhs->right = rhs; newlhs->op = op; lhs = newlhs; } else if(Operator::isComparison(op)) { if(auto cmp = dcast(ComparisonOp, lhs)) { cmp->ops.push_back({ op, loc }); cmp->exprs.push_back(rhs); lhs = cmp; } else { iceAssert(lhs); auto newlhs = util::pool(loc); newlhs->exprs.push_back(lhs); newlhs->exprs.push_back(rhs); newlhs->ops.push_back({ op, loc }); lhs = newlhs; } } else { lhs = util::pool(loc, op, dcast(Expr, lhs), rhs); } } } Expr* parseCaretOrColonScopeExpr(State& st) { iceAssert(zfu::match(st.front(), TT::DoubleColon, TT::Caret)); auto str = st.front().str(); auto loc = st.loc(); if(st.front() == TT::Caret) { st.eat(); if(st.front() != TT::DoubleColon) expectedAfter(st.loc(), "'::'", "'^' in scope-path-specifier", st.front().str()); } // ^::(^::((foo::bar)::qux)) auto ident = util::pool(loc, str); return parseRhs(st, ident, tok_precedence(st, TT::DoubleColon)); } static Expr* parseTuple(State& st, Expr* lhs) { iceAssert(lhs); std::vector values { lhs }; Token t = st.front(); while(true) { values.push_back(parseExpr(st)); if(st.front().type == TT::RParen) break; if(st.front().type != TT::Comma) expected(st, "either ')' or ',' in tuple", st.front().str()); st.eat(); t = st.front(); } // leave the last rparen iceAssert(st.front().type == TT::RParen); Location loc = lhs->loc; loc.col -= 1; loc.len = (st.front().loc.col - loc.col + 1); return util::pool(loc, values); } Expr* parseDollarExpr(State& st) { if(st.isInSubscript()) { return util::pool(st.pop().loc); } else { unexpected(st.loc(), "'$' in non-subscript context"); return nullptr; // PRESULT FIXUP } } static Expr* parseParenthesised(State& st) { Token opening = st.eat(); iceAssert(opening.type == TT::LParen); if(st.front() == TT::RParen) error(st.loc(), "empty tuples are not supported"); Expr* within = parseExpr(st); st.skipWS(); if(st.front().type != TT::Comma && st.front().type != TT::RParen) { SpanError::make(SimpleError::make(st.loc(), "expected ',' to begin a tuple, or a closing ')'"))->add( util::ESpan(opening.loc, "opening parenthesis was here") )->append(BareError::make(MsgType::Note, "named tuples are not supported"))->postAndQuit(); } // if we're a tuple, get ready for this shit. if(st.front().type == TT::Comma) { // remove the comma st.eat(); // parse a tuple Expr* tup = parseTuple(st, within); within = tup; } iceAssert(st.front().type == TT::RParen); st.eat(); return within; } static Expr* parseUnary(State& st) { auto tk = st.front(); // check for unary shit std::string op; //* note: we use the binary versions of the operator; since the unary AST and binary AST are separate, //* there's no confusion here. It also makes custom operators less troublesome to implement. if(tk.type == TT::Exclamation || tk.type == TT::Plus || tk.type == TT::Minus || tk.type == TT::Tilde || tk.type == TT::Asterisk || tk.type == TT::Ampersand || tk.type == TT::Ellipsis) { op = tk.str(); } int prec = -1; if(auto it = st.prefixOps.find(tk.str()); op.empty() && it != st.prefixOps.end()) { // great. auto cop = it->second; iceAssert(cop.kind == CustomOperatorDecl::Kind::Prefix); prec = cop.precedence; op = cop.symbol; // debuglog("symbol = '%s'\n", op); } else { prec = unaryPrecedence(op); } if(op == "...") { st.eat(); Expr* e = parseUnary(st); auto ret = util::pool(tk.loc); ret->expr = e; return ret; } else if(!op.empty()) { st.eat(); Expr* un = parseUnary(st); Expr* thing = parseRhs(st, un, prec); auto ret = util::pool(tk.loc); ret->expr = thing; ret->op = op; return ret; } else { return parsePrimary(st); } } std::vector> parseCallArgumentList(State& st) { std::unordered_set seenNames; std::vector> ret; while(st.front() != TT::RParen) { std::string argname; auto ex = parseExpr(st); if(auto id = dcast(Ident, ex); id && st.front() == TT::Colon) { argname = id->name; if(seenNames.find(argname) != seenNames.end()) error(id->loc, "argument '%s' was already provided", argname); seenNames.insert(argname); // eat the colon, get the actual argument. st.eat(); ex = parseExpr(st); } ret.push_back({ argname, ex }); st.skipWS(); if(st.front() == TT::Comma) st.pop(); else if(st.front() != TT::RParen) expected(st, "',' or ')' in function call argument list", st.front().str()); } iceAssert(st.front().type == TT::RParen); st.pop(); return ret; } static FunctionCall* parseFunctionCall(State& st, const Location& loc, const std::string& name) { auto ret = util::pool(loc, name); st.skipWS(); ret->args = parseCallArgumentList(st); return ret; } static Expr* parseCall(State& st, Expr* lhs, Token op) { if(Ident* id = dcast(Ident, lhs)) { auto ret = parseFunctionCall(st, id->loc, id->name); ret->mappings = id->mappings; return ret; } auto ret = util::pool(op.loc); iceAssert(op == TT::LParen); ret->args = parseCallArgumentList(st); ret->callee = lhs; return ret; } static Expr* parseIdentifier(State& st) { iceAssert(zfu::match(st.front(), TT::Identifier, TT::UnicodeSymbol)); std::string name = st.pop().str(); auto ident = util::pool(st.ploc(), name); //* we've modified our generic thing to be Foo!<...>, so there shouldn't //* be any ambiguity left. once we see '!' and '<' we know for sure. //? as long as we don't make '!' a postfix operator... //? for now, we'll leave in the try-and-restore mechanism. if(st.front() == TT::Exclamation && st.lookahead(1) == TT::LAngle) { bool fail = false; auto restore = st.getIndex(); auto pams = parsePAMs(st, &fail); if(fail) { st.rewindTo(restore); } else { ident->mappings = pams; ident->loc.len += (st.ploc().col - st.getTokenList()[restore].loc.col) + 1; } } return ident; } static Expr* parsePostfixUnary(State& st, Expr* lhs, Token op) { if(op.type == TT::LParen) { return parseCall(st, lhs, op); } else if(op.type == TT::LSquare) { st.enterSubscript(); defer(st.leaveSubscript()); // if we're a colon immediately, then it's a slice expr already. // either [:x] or [:] Expr* slcbegin = 0; Expr* slcend = 0; bool isSlice = false; if(st.front().type == TT::Colon) { st.eat(); isSlice = true; if(st.front().type == TT::RSquare) { st.eat(); // just return here. auto ret = util::pool(op.loc); ret->expr = lhs; ret->start = 0; ret->end = 0; return ret; } } // parse the inside expression Expr* inside = parseExpr(st); if(!isSlice && st.front().type == TT::RSquare) { auto end = st.eat().loc; iceAssert(inside); auto ret = util::pool(op.loc); ret->expr = lhs; ret->inside = inside; // custom thingy ret->loc.col = lhs->loc.col; ret->loc.len = end.col - ret->loc.col + 1; return ret; } else if(isSlice && st.front().type == TT::RSquare) { st.eat(); // x[:N] slcbegin = 0; slcend = inside; auto ret = util::pool(op.loc); ret->expr = lhs; ret->start = slcbegin; ret->end = slcend; return ret; } else if(st.front().type == TT::Colon) { st.eat(); // x[N:M] slcbegin = inside; if(st.front() != TT::RSquare) slcend = parseExpr(st); //* note: looks duplicated and wrong, but rest assured it's fine. if we get arr[x:], that's valid. if(st.front() != TT::RSquare) expectedAfter(st.loc(), "']'", "expression for slice operation", st.front().str()); st.eat(); auto ret = util::pool(op.loc); ret->expr = lhs; ret->start = slcbegin; ret->end = slcend; return ret; } else { expectedAfter(st.loc(), "']'", "'[' for array subscript", st.front().str()); } } else if(auto it = st.postfixOps.find(op.str()); it != st.postfixOps.end()) { // yay...? //* note: custom postfix ops are handled internally in the AST as normal unary ops. auto ret = util::pool(op.loc); ret->expr = lhs; ret->op = op.str(); ret->isPostfix = true; return ret; } else { // todo: ++ and --. error("enotsup"); } return nullptr; // PRESULT FIXUP } static Expr* parseAlloc(State& st, bool raw) { iceAssert(st.front() == TT::Alloc); auto loc = st.eat().loc; auto ret = util::pool(loc); if(st.front() == TT::Mutable) ret->isMutable = true, st.pop(); if(raw) ret->attrs.set(attr::RAW); ret->allocTy = parseType(st); if(st.front() == TT::LParen) { auto leftloc = st.loc(); st.pop(); ret->args = parseCallArgumentList(st); if(ret->args.empty()) { // parseCallArgumentList consumes the closing ) auto tmp = Location::unionOf(leftloc, st.ploc()); info(tmp, "empty argument list in alloc expression () can be omitted"); } } if(st.front() == TT::LSquare) { st.eat(); while(st.front() != TT::RSquare) { ret->counts.push_back(parseExpr(st)); if(st.front() == TT::Comma) st.eat(); else if(st.front() != TT::RSquare) expected(st.loc(), "',' or ')' in dimension list for alloc expression", st.front().str()); } if(st.eat() != TT::RSquare) expectedAfter(st.ploc(), "']'", "'alloc(...)'", st.prev().str()); if(ret->counts.empty()) error(st.ploc(), "dimension list in 'alloc' cannot be empty"); } if(st.front() == TT::LBrace) { if(raw) error(st.loc(), "initialisation body cannot be used with raw array allocations"); // ok, get it ret->initBody = parseBracedBlock(st).val(); } return ret; } DeallocOp* parseDealloc(State& st) { iceAssert(st.front() == TT::Dealloc); auto loc = st.eat().loc; auto ret = util::pool(loc); ret->expr = parseExpr(st); return ret; } DeferredStmt* parseDefer(State& st) { iceAssert(st.front() == TT::Defer); auto ret = util::pool(st.eat().loc); if(st.front() == TT::LBrace) ret->actual = parseBracedBlock(st).val(); else ret->actual = parseStmt(st).val(); return ret; } SizeofOp* parseSizeof(State& st) { Token tok = st.eat(); iceAssert(tok == TT::Sizeof); if(st.eat() != TT::LParen) expectedAfter(st.ploc(), "'('", "sizeof", st.prev().str()); auto ret = util::pool(tok.loc); ret->expr = parseExpr(st); if(st.eat() != TT::RParen) expectedAfter(st.ploc(), "')'", "expression in sizeof", st.prev().str()); return ret; } TypeidOp* parseTypeid(State& st) { Token tok = st.eat(); iceAssert(tok == TT::Typeid); if(st.eat() != TT::LParen) expectedAfter(st.ploc(), "'('", "typeid", st.prev().str()); auto ret = util::pool(tok.loc); ret->expr = parseExpr(st); if(st.eat() != TT::RParen) expectedAfter(st.ploc(), "')'", "expression in typeid", st.prev().str()); return ret; } Expr* parseExpr(State& st) { Expr* lhs = parseUnary(st); iceAssert(lhs); return parseRhs(st, lhs, 0); } static Expr* parsePrimary(State& st) { if(!st.hasTokens()) unexpected(st, "end of file"); st.skipWS(); auto tok = st.front(); if(tok != TT::EndOfFile) { switch(tok.type) { case TT::Var: case TT::Val: case TT::Func: case TT::Enum: case TT::Class: case TT::Using: case TT::Union: case TT::Static: case TT::Struct: case TT::Public: case TT::Private: case TT::Operator: case TT::Trait: case TT::Internal: case TT::Override: case TT::Extension: case TT::Namespace: case TT::TypeAlias: case TT::ForeignFunc: error(st, "declarations are not expressions (%s)", tok.str()); case TT::Dealloc: error(st, "deallocation statements are not expressions"); case TT::Defer: error(st, "defer statements are not expressions"); case TT::Return: error(st, "return statements are not expressions"); case TT::Break: error(st, "break statements are not expressions"); case TT::Continue: error(st, "continue statements are not expressions"); case TT::If: error(st, "if statements are not expressions"); case TT::Do: case TT::While: case TT::For: error(st, "loops are not expressions"); case TT::Dollar: return parseDollarExpr(st); case TT::LParen: return parseParenthesised(st); case TT::Identifier: case TT::UnicodeSymbol: return parseIdentifier(st); case TT::Caret: case TT::DoubleColon: return parseCaretOrColonScopeExpr(st); case TT::Alloc: return parseAlloc(st, false); // case TT::Typeof: // return parseTypeof(ps); case TT::Typeid: return parseTypeid(st); case TT::Sizeof: return parseSizeof(st); case TT::Attr_Raw: st.pop(); if(st.front() == TT::StringLiteral) return parseString(st, /* isRaw: */ true); else if(st.front() == TT::LSquare) return parseArray(st, /* isRaw: */ true); else if(st.front() == TT::Alloc) return parseAlloc(st, /* isRaw: */ true); else expectedAfter(st, "one of string-literal, array, or alloc", "'@raw' while parsing expression", st.front().str()); case TT::StringLiteral: return parseString(st, false); case TT::Number: return parseNumber(st); case TT::LSquare: return parseArray(st, /* isRaw: */ false); case TT::CharacterLiteral: st.pop(); return util::pool(tok.loc, static_cast(tok.text[0])); // no point creating separate functions for these case TT::True: st.pop(); return util::pool(tok.loc, true); case TT::False: st.pop(); return util::pool(tok.loc, false); // nor for this case TT::Null: st.pop(); return util::pool(tok.loc); case TT::Directive_Run: return parseRunDirective(st); case TT::LBrace: unexpected(st, "block; to create a nested scope, use 'do { ... }'"); default: error(tok.loc, "unexpected token '%s' (id = %d)", tok.str(), tok.type); } } return 0; } } ================================================ FILE: source/frontend/parser/function.cpp ================================================ // function.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "defs.h" #include "pts.h" #include "parser_internal.h" #include "memorypool.h" using namespace ast; using namespace lexer; using TT = lexer::TokenType; namespace parser { std::tuple, std::vector>, pts::Type*, bool, Location> parseFunctionLookingDecl(State& st) { pts::Type* returnType = 0; std::vector params; std::vector> generics; // check for generic function if(st.front() == TT::LAngle) { st.eat(); // parse generic if(st.front() == TT::RAngle) error(st, "empty type parameter lists are not allowed"); generics = parseGenericTypeList(st); } if(st.front() != TT::LParen) expectedAfter(st, "'('", "function declaration to begin argument list", st.front().str()); st.eat(); Location varloc; bool isfvar = false; // flax-variadic bool iscvar = false; // c-variadic bool startedOptional = false; while(st.front() != TT::RParen) { st.skipWS(); if(iscvar || isfvar) error(st, "variadic parameter list must be the last function parameter"); if(st.front() == TT::Ellipsis) { iscvar = true; varloc = st.loc(); st.pop(); continue; } if(st.front() != TT::Identifier) expected(st, "identifier in function parameter list", st.front().str()); std::string name = st.front().str(); auto loc = st.loc(); st.eat(); if(st.front() != TT::Colon) expected(st, "':' after identifier to specify type", st.front().str()); st.eat(); auto type = parseType(st); if(type->isVariadicArrayType()) isfvar = true; Expr* defaultVal = 0; if(st.front() == TT::Equal) { if(type->isVariadicArrayType()) error(st, "variadic parameter list cannot have a default value"); st.pop(); startedOptional = true; defaultVal = parseExpr(st); } // we can have a variadic list after optional arguments else if(startedOptional && !isfvar) { error(loc, "mandatory arguments must be declared before any optional arguments"); } params.push_back(FuncDefn::Param { name, loc, type, defaultVal }); if(st.front() == TT::Comma) st.eat(); else if(st.front() != TT::RParen) expected(st, "')' or ',' in function parameter list", st.front().str()); st.skipWS(); } iceAssert(st.front() == TT::RParen); st.eat(); if(st.front() == TT::RightArrow) { st.eat(); returnType = parseType(st); } else { returnType = 0; } return std::make_tuple(params, generics, returnType, iscvar, varloc); } std::tuple parseFunctionDecl(State& st) { iceAssert(st.front() == TT::Func); st.eat(); if(st.front() != TT::Identifier) expectedAfter(st, "identifier", "'fn'", st.front().str()); FuncDefn* defn = util::pool(st.loc()); defn->name = st.eat().str(); Location loc; bool isvar = false; std::tie(defn->params, defn->generics, defn->returnType, isvar, loc) = parseFunctionLookingDecl(st); if(defn->returnType == 0) defn->returnType = pts::NamedType::create(defn->loc, VOID_TYPE_STRING); return std::make_tuple(defn, isvar, loc); } PResult parseFunction(State& st) { auto [ defn, isvar, varloc ] = parseFunctionDecl(st); if(isvar) error(varloc, "C-style variadic arguments are not supported on non-foreign functions"); st.skipWS(); if(st.front() != TT::LBrace && st.front() != TT::FatRightArrow) expected(st, "'{' to begin function body", st.front().str()); st.enterFunctionBody(); { auto body = parseBracedBlock(st); if(body.hasValue()) defn->body = body.val(); else return PResult::copyError(body); } st.leaveFunctionBody(); return defn; } ForeignFuncDefn* parseForeignFunction(State& st) { iceAssert(st.front() == TT::ForeignFunc); st.pop(); st.skipWS(); if(st.front() != TT::Func) expectedAfter(st, "'fn'", "'ffi'", st.front().str()); auto ffn = util::pool(st.loc()); // copy the things over auto [ defn, isvar, varloc ] = parseFunctionDecl(st); (void) varloc; if(!defn->generics.empty()) error(ffn->loc, "foreign functions cannot be generic"); ffn->loc = defn->loc; ffn->isVarArg = isvar; ffn->name = defn->name; ffn->params = defn->params; ffn->visibility = defn->visibility; ffn->returnType = defn->returnType; // make sure we don't have optional arguments here zfu::foreach(ffn->params, [](const auto& a) { if(a.defaultValue) error(a.loc, "foreign functions cannot have optional arguments"); }); // check for 'as' if(st.front() == TT::As) { st.pop(); if(st.front() != TT::StringLiteral) expectedAfter(st.loc(), "string literal", "'as' in foreign function declaration", st.front().str()); ffn->realName = parseStringEscapes(st.loc(), st.eat().str()); } else { ffn->realName = ffn->name; } return ffn; } InitFunctionDefn* parseInitFunction(State& st) { Token tok = st.pop(); iceAssert(tok.str() == "init"); auto [ params, generics, retty, isvar, varloc ] = parseFunctionLookingDecl(st); if(generics.size() > 0) error(st.ploc(), "class initialiser functions cannot be generic"); else if(retty != 0) error(st.ploc(), "class initialisers cannot have a return type"); else if(isvar) error(varloc, "C-style variadic arguments are not supported on non-foreign functions"); // ok loh auto ret = util::pool(tok.loc); ret->name = "init"; ret->params = params; // check for super-class args. if(st.front() == TT::Colon) { st.eat(); if(st.eat().str() != "super") expectedAfter(st.ploc(), "'super'", "':' in init function definition", st.prev().str()); if(st.eat() != TT::LParen) expectedAfter(st.ploc(), "'('", "'super' in call to base-class initialiser", st.prev().str()); ret->superArgs = parseCallArgumentList(st); ret->didCallSuper = true; } st.enterFunctionBody(); { ret->body = parseBracedBlock(st).val(); } st.leaveFunctionBody(); return ret; } InitFunctionDefn* parseCopyOrMoveInitFunction(State& st, const std::string& name) { Token tok = st.pop(); iceAssert(tok.str() == name); auto [ params, generics, retty, isvar, varloc ] = parseFunctionLookingDecl(st); if(generics.size() > 0) error(st.ploc(), "class initialiser functions cannot be generic"); else if(retty != 0) error(st.ploc(), "class initialisers cannot have a return type"); else if(isvar) error(varloc, "C-style variadic arguments are not supported on non-foreign functions"); // ok loh auto ret = util::pool(tok.loc); ret->name = name; ret->params = params; st.enterFunctionBody(); { ret->body = parseBracedBlock(st).val(); } st.leaveFunctionBody(); return ret; } InitFunctionDefn* parseDeinitFunction(State& st) { Token tok = st.pop(); iceAssert(tok.str() == "deinit"); auto ret = util::pool(tok.loc); ret->name = "deinit"; st.enterFunctionBody(); { ret->body = parseBracedBlock(st).val(); } st.leaveFunctionBody(); return ret; } std::vector> parseGenericTypeList(State& st) { std::unordered_set seen; std::vector> ret; while(st.front().type != TT::RAngle) { if(st.front().type == TT::Identifier) { std::string gt = st.eat().str(); TypeConstraints_t constrs; if(st.front().type == TT::Colon) { st.eat(); if(st.front().type != TT::Identifier) error(st, "expected identifier after beginning of type constraint list"); while(st.front().type == TT::Identifier) { constrs.protocols.push_back(st.eat().str()); if(st.front().type == TT::Ampersand) { st.eat(); } else if(st.front().type != TT::Comma && st.front().type != TT::RAngle) { error(st, "expected ',' or '>' to end type parameter list (1)"); } } } else if(st.front().type != TT::Comma && st.front().type != TT::RAngle) { error(st, "expected ',' or '>' to end type parameter list (2)"); } if(seen.find(gt) != seen.end()) error(st, "duplicate type parameter '%s'", gt); seen.insert(gt); ret.push_back({ gt, constrs }); } else if(st.front().type == TT::Comma) { st.eat(); } else if(st.front().type != TT::RAngle) { error(st, "expected '>' to end type parameter list"); } } iceAssert(st.front().type == TT::RAngle); st.eat(); return ret; } PResult parseBracedBlock(State& st) { st.skipWS(); if(st.front() == TT::LBrace) { Block* ret = util::pool(st.eat().loc); st.skipWS(); while(st.front() != TT::RBrace) { if(!st.hasTokens()) return PResult::insufficientTokensError(); auto s = parseStmt(st).mutate([&](auto stmt) { if(auto defer = dcast(DeferredStmt, stmt)) ret->deferredStatements.push_back(defer); else ret->statements.push_back(stmt); if(st.front() == TT::NewLine || st.front() == TT::Comment || st.front() == TT::Semicolon) st.pop(); else if(st.frontAfterWS() == TT::RBrace) return; else expected(st, "newline or semicolon to terminate a statement", st.front().str()); st.skipWS(); }); if(s.isError()) return PResult::copyError(s); } auto closing = st.eat(); iceAssert(closing == TT::RBrace); ret->closingBrace = closing.loc; ret->isArrow = false; return ret; } else if(st.front() == TT::FatRightArrow) { Block* ret = util::pool(st.eat().loc); ret->statements.push_back(parseStmt(st).val()); ret->closingBrace = st.loc(); ret->isArrow = true; return ret; } else { expected(st, "'{' to begin braced block", st.front().str()); } } } ================================================ FILE: source/frontend/parser/literal.cpp ================================================ // literal.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "defs.h" #include "platform.h" #include "parser_internal.h" #include "memorypool.h" #include "utf8rewind/include/utf8rewind/utf8rewind.h" #include using namespace ast; using namespace lexer; using TT = lexer::TokenType; namespace parser { LitNumber* parseNumber(State& st) { iceAssert(st.front() == TT::Number); auto t = st.eat(); return util::pool(st.ploc(), t.str()); } static std::string parseHexEscapes(const Location& loc, std::string_view sv, size_t* ofs) { if(sv[0] == 'x') { if(sv.size() < 3) error(loc, "malformed escape sequence: unexpected end of string"); if(!isxdigit(sv[1]) || !isxdigit(sv[2])) error(loc, "malformed escape sequence: non-hex character in \\x escape"); // ok then. char s[2] = { sv[1], sv[2] }; char val = static_cast(std::stol(s, /* pos: */ 0, /* base: */ 16)); *ofs = 3; return std::string(&val, 1); } else if(sv[0] == 'u') { if(sv.size() < 3) error(loc, "malformed escape sequence: unexpected end of string"); sv.remove_prefix(1); if(sv[0] != '{') error(loc, "malformed escape sequence: expected '{' after \\u"); sv.remove_prefix(1); std::string digits; size_t i = 0; for(i = 0; i < sv.size(); i++) { if(sv[i] == '}') break; if(!isxdigit(sv[i])) error(loc, "malformed escape sequence: non-hex character '%c' inside \\u{...}", sv[i]); if(digits.size() == 8) error(loc, "malformed escape sequence: too many digits inside \\u{...}; up to 8 are allowed"); digits += sv[i]; } if(sv[i] != '}') error(loc, "malformed escape sequence: expcected '}' to end codepoint escape"); uint32_t codepoint = std::stol(digits, /* pos: */ 0, /* base: */ 16); char output[8] = { 0 }; int err = 0; auto sz = utf32toutf8(&codepoint, 4, output, 8, &err); if(err != UTF8_ERR_NONE) error(loc, "invalid utf32 codepoint!"); *ofs = 3 + digits.size(); return std::string(output, sz); } else { iceAssert("wtf yo" && 0); return ""; } } std::string parseStringEscapes(const Location& loc, const std::string& str) { std::stringstream ss; for(size_t i = 0; i < str.length(); i++) { if(str[i] == '\\') { i++; switch(str[i]) { case 'n': ss << "\n"; break; case 'b': ss << "\b"; break; case 'r': ss << "\r"; break; case 't': ss << "\t"; break; case '"': ss << "\""; break; case '\\': ss << "\\"; break; case 'x': // fallthrough case 'u': { size_t ofs = 0; ss << parseHexEscapes(loc, std::string_view(str.c_str() + i, str.size() - i), &ofs); i += ofs - 1; break; } default: ss << std::string("\\") + str[i]; break; } } else { ss << str[i]; } } return ss.str(); } LitString* parseString(State& st, bool israw) { iceAssert(st.front() == TT::StringLiteral); auto t = st.eat(); return util::pool(st.ploc(), parseStringEscapes(st.ploc(), t.str()), israw); } LitArray* parseArray(State& st, bool israw) { iceAssert(st.front() == TT::LSquare); Token front = st.eat(); pts::Type* explType = 0; if(st.front() == TT::As) { // get an explicit type. st.pop(); explType = parseType(st); if(st.pop() != TT::Colon) expectedAfter(st.ploc(), ":", "explicit type in array literal", st.prev().str()); } std::vector values; while(true) { Token tok = st.frontAfterWS(); if(tok.type == TT::Comma) { st.pop(); if(st.frontAfterWS() == TT::RSquare) error(tok.loc, "trailing commas are not allowed"); continue; } else if(tok.type == TT::RSquare) { break; } else { st.skipWS(); values.push_back(parseExpr(st)); } } st.skipWS(); iceAssert(st.front() == TT::RSquare); auto end = st.eat(); auto ret = util::pool(front.loc, values); ret->explicitType = explType; // don't matter if null. ret->raw = israw; // ret->loc.col = front.loc.col + 1; ret->loc.len = (end.loc.col - front.loc.col) + 1; return ret; } } ================================================ FILE: source/frontend/parser/misc.cpp ================================================ // misc.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "frontend.h" #include "parser_internal.h" #include "memorypool.h" using namespace ast; using namespace lexer; namespace parser { using TT = lexer::TokenType; ImportStmt* parseImport(State& st) { iceAssert(st.front() == TT::Import); auto ret = util::pool(st.loc()); st.eat(); st.skipWS(); if(st.front() == TT::StringLiteral) { st.eat(); } else if(st.front() == TT::Identifier) { // just consume. size_t i = st.getIndex(); parseIdentPath(st.getTokenList(), &i); st.setIndex(i); } else { expectedAfter(st, "string literal or identifier path", "'import'", st.front().str()); } { st.skipWS(); // check for 'import as foo' if(st.front() == TT::As) { st.eat(); if(st.front() != TT::Identifier) expectedAfter(st.loc(), "identifier", "'import-as'", st.front().str()); size_t i = st.getIndex(); parseIdentPath(st.getTokenList(), &i); st.setIndex(i); } return ret; } } UsingStmt* parseUsingStmt(State& st) { iceAssert(st.front() == TT::Using); st.eat(); st.enterUsingParse(); defer(st.leaveUsingParse()); auto ret = util::pool(st.ploc()); ret->expr = parseExpr(st); if(st.front() != TT::As) expectedAfter(st.loc(), "'as'", "scope in 'using'", st.front().str()); st.eat(); if(st.front() != TT::Identifier) expectedAfter(st.loc(), "identifier", "'as' in 'using' declaration", st.front().str()); ret->useAs = st.eat().str(); return ret; } RunDirective* parseRunDirective(State& st) { iceAssert(st.front() == TT::Directive_Run); auto ret = util::pool(st.eat().loc); // trick the parser. when we do a #run, we will run it in a function wrapper, so we // are technically "inside" a function. st.enterFunctionBody(); defer(st.leaveFunctionBody()); if(st.front() == TT::LBrace) ret->block = parseBracedBlock(st).val(); else ret->insideExpr = parseExpr(st); return ret; } AttribSet parseAttributes(State& st) { using UA = AttribSet::UserAttrib; if(st.front() != TT::At && (st.front() <= TT::Attr_ATTRS_BEGIN || st.front() >= TT::Attr_ATTRS_END)) return AttribSet::of(attr::NONE); auto parseUA = [](State& st) -> UA { iceAssert(st.front() == TT::At); st.pop(); auto ret = UA(st.eat().str(), {}); if(st.front() == TT::LSquare) { auto begin = st.loc(); st.eat(); //* this means that attributes can only take tokens as arguments. if you want more complex stuff, //* then it needs to be wrapped up in a string literal. while(st.front() != TT::RSquare) { ret.args.push_back(st.eat().str()); if(st.front() == TT::Comma) st.eat(); else if(st.front() != TT::RSquare) expected(st.loc(), "']' to end argument list", st.prev().str()); } iceAssert(st.front() == TT::RSquare); st.pop(); if(ret.args.empty()) warn(Location::unionOf(begin, st.ploc()), "empty argument list to attribute"); } return ret; }; AttribSet ret; while(true) { // i would love me some static reflection right now switch(st.front()) { case TT::Attr_Raw: ret.set(attr::RAW); st.pop(); break; case TT::Attr_Packed: ret.set(attr::PACKED); st.pop(); break; case TT::Attr_NoMangle: ret.set(attr::NO_MANGLE); st.pop(); break; case TT::Attr_EntryFn: ret.set(attr::FN_ENTRYPOINT); st.pop(); break; case TT::Attr_Platform: unexpected(st.loc(), "@platform definition"); case TT::Attr_Operator: unexpected(st.loc(), "@operator declaration"); case TT::At: ret.add(parseUA(st)); break; default: goto out; } } // sue me out: return ret; } // TODO: switch this to the new attribute system. after the whole cddc19 shitshow @platform functionality // TODO: remains unused. PlatformDefn* parsePlatformDefn(State& st) { iceAssert(st.front() == TT::Attr_Platform); auto l = st.loc(); st.eat(); if(st.eat() != TT::LSquare) expectedAfter(st.ploc(), "'['", "@platform definition", st.prev().str()); PlatformDefn* pd = util::pool(l); // see what the thing is. if(st.front() == TT::Identifier && st.front().str() == "intrinsic") { st.eat(); pd->defnType = PlatformDefn::Type::Intrinsic; if(st.eat() != TT::Comma) expected(st.ploc(), "',' in argument list to @platform", st.prev().str()); if(st.front() != TT::StringLiteral) expected(st.loc(), "string literal to specify intrinsic name", st.front().str()); auto realname = st.eat().str(); if(st.eat() != TT::RSquare) expectedAfter(st.ploc(), "']'", "@platform definition", st.prev().str()); if(st.front() != TT::Func) expectedAfter(st.loc(), "function declaration", "@platform", st.front().str()); auto [ defn, isvar, varloc ] = parseFunctionDecl(st); (void) varloc; if(!defn->generics.empty()) error(defn->loc, "platform intrinsics cannot be generic"); auto ffn = util::pool(st.loc()); ffn->realName = realname; ffn->loc = defn->loc; ffn->isVarArg = isvar; ffn->name = defn->name; ffn->params = defn->params; ffn->visibility = defn->visibility; ffn->returnType = defn->returnType; pd->intrinsicDefn = ffn; } else if(st.front() == TT::Identifier && st.front().str() == "integer_type") { st.eat(); pd->defnType = PlatformDefn::Type::IntegerType; if(st.eat() != TT::Comma) expected(st.ploc(), "',' in argument list to @platform", st.prev().str()); auto num = st.front().str(); if(st.front() != TT::Number || num.find('.') != std::string::npos) expected(st.ploc(), "integer value to specify type size (in bits)", st.front().str()); st.eat(); int sz = std::stoi(num); if(sz <= 0) expected(st.ploc(), "non-zero and non-negative size", num); else if(sz < 8) error(st.ploc(), "types less than 8-bits wide are currently not supported"); pd->typeSizeInBits = sz; if(st.eat() != TT::RSquare) expectedAfter(st.ploc(), "']'", "@platform definition", st.prev().str()); if(st.front() != TT::Identifier) expectedAfter(st.loc(), "identifier as type name", "@platform definition", st.front().str()); pd->typeName = st.eat().str(); } else if(st.front() == TT::Identifier && st.front().str() == "native_word_size") { if(!st.nativeWordSizeStillValid) { SimpleError::make(st.loc(), "setting the native word size is no longer possible at this point")->append( BareError::make(MsgType::Note, "@platform[native_word_size] must appear before any code declarations, " "and be the first '@platform' declaration"))->postAndQuit(); } st.eat(); if(st.eat() != TT::RSquare) expectedAfter(st.ploc(), "']'", "@platform definition", st.prev().str()); auto num = st.front().str(); if(st.front() != TT::Number || num.find('.') != std::string::npos) expected(st.ploc(), "integer value to specify word size (in bits)", st.front().str()); st.eat(); int sz = std::stoi(num); if(sz <= 0) expected(st.ploc(), "non-zero and non-negative size", num); else if(sz < 8) error(st.ploc(), "types less than 8-bits wide are currently not supported"); //? should we warn if it was already set? st.cState->nativeWordSize = sz; return 0; } else { error(st.loc(), "invalid platform declaration of type '%s'", st.front().str()); } return pd; } } ================================================ FILE: source/frontend/parser/operators.cpp ================================================ // operators.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "defs.h" #include "pts.h" #include "parser.h" #include "parser_internal.h" #include "memorypool.h" using namespace ast; using namespace lexer; using TT = lexer::TokenType; namespace parser { OperatorOverloadDefn* parseOperatorOverload(State& st) { using Kind = OperatorOverloadDefn::Kind; iceAssert(st.front() == TT::Operator); auto ret = util::pool(st.eat().loc); if(st.front().str() == "prefix") ret->kind = Kind::Prefix; else if(st.front().str() == "postfix") ret->kind = Kind::Postfix; else if(st.front().str() == "infix") ret->kind = Kind::Infix; else expectedAfter(st, "either 'infix', 'prefix' or 'postfix'", "'operator'", st.front().str()); st.eat(); ret->symbol = parseOperatorTokens(st); bool isvar = false; std::tie(ret->params, ret->generics, ret->returnType, isvar, std::ignore) = parseFunctionLookingDecl(st); if(ret->returnType == 0) ret->returnType = pts::NamedType::create(ret->loc, VOID_TYPE_STRING); if(isvar) error(ret, "C-style variadic arguments are not supported on non-foreign functions"); st.skipWS(); if(st.front() != TT::LBrace && st.front() != TT::FatRightArrow) expected(st, "'{' to begin function body", st.front().str()); st.enterFunctionBody(); ret->body = parseBracedBlock(st).val(); ret->name = ret->symbol; st.leaveFunctionBody(); return ret; } std::string parseOperatorTokens(State& st) { using TT = lexer::TokenType; auto tok_op = st.eat(); if(tok_op == TT::LAngle || tok_op == TT::RAngle) { // check if the next one matches. if(tok_op == TT::LAngle) { if(st.front() == TT::LAngle) { // < < is << st.eat(); return Operator::BitwiseShiftLeft; } else if(st.front() == TT::LessThanEquals) { // < <= is <<= st.eat(); return Operator::BitwiseShiftLeftEquals; } } else if(tok_op == TT::RAngle) { if(st.front() == TT::RAngle) { // > > is >> st.eat(); return Operator::BitwiseShiftRight; } else if(st.front() == TT::GreaterEquals) { // > >= is >>= st.eat(); return Operator::BitwiseShiftRightEquals; } } } switch(tok_op.type) { case TT::Plus: return Operator::Plus; case TT::Minus: return Operator::Minus; case TT::Asterisk: return Operator::Multiply; case TT::Divide: return Operator::Divide; case TT::Percent: return Operator::Modulo; case TT::Equal: return Operator::Assign; case TT::LAngle: return Operator::CompareLT; case TT::RAngle: return Operator::CompareGT; case TT::LessThanEquals: return Operator::CompareLEQ; case TT::GreaterEquals: return Operator::CompareGEQ; case TT::EqualsTo: return Operator::CompareEQ; case TT::NotEquals: return Operator::CompareNEQ; case TT::Ampersand: return Operator::BitwiseAnd; case TT::Pipe: return Operator::BitwiseOr; case TT::Caret: return Operator::BitwiseXor; case TT::LogicalOr: return Operator::LogicalOr; case TT::LogicalAnd: return Operator::LogicalAnd; case TT::PlusEq: return Operator::PlusEquals; case TT::MinusEq: return Operator::MinusEquals; case TT::MultiplyEq: return Operator::MultiplyEquals; case TT::DivideEq: return Operator::DivideEquals; case TT::ModEq: return Operator::ModuloEquals; case TT::AmpersandEq: return Operator::BitwiseAndEquals; case TT::PipeEq: return Operator::BitwiseOrEquals; case TT::CaretEq: return Operator::BitwiseXorEquals; case TT::As: return Operator::TypeCast; case TT::Is: return Operator::TypeIs; case TT::DoubleColon: return "::"; case TT::Period: return "."; case TT::At: return "@"; case TT::Ellipsis: return "..."; case TT::HalfOpenEllipsis: return "..<"; default: break; } // check custom operators. if(tok_op.type == TT::Identifier || tok_op.type == TT::UnicodeSymbol) return tok_op.str(); return ""; } // TODO: move this over to the new attribute system if possible. size_t parseOperatorDecl(const lexer::TokenList& tokens, size_t idx, int* _kind, CustomOperatorDecl* out) { iceAssert(tokens[idx] == TT::Attr_Operator); const Token tok = tokens[idx]; using Kind = CustomOperatorDecl::Kind; CustomOperatorDecl oper; oper.loc = tok.loc; idx++; if(tokens[idx] != TT::LSquare) expectedAfter(tokens[idx].loc, "'['", "'@operator' in custom operator declaration", tokens[idx].str()); idx++; if(tokens[idx].str() != "prefix" && tokens[idx].str() != "postfix" && tokens[idx].str() != "infix") { expectedAfter(tokens[idx].loc, "either 'prefix', 'postfix' or 'infix'", "'@operator' in custom operator declaration", tokens[idx].str()); } int kind = 0; if(tokens[idx].str() == "infix") kind = 1, oper.kind = Kind::Infix; else if(tokens[idx].str() == "prefix") kind = 2, oper.kind = Kind::Prefix; else if(tokens[idx].str() == "postfix") kind = 3, oper.kind = Kind::Postfix; else iceAssert(0); idx++; if(tokens[idx] != TT::Comma) expected(tokens[idx].loc, "',' in argument list to '@operator'", tokens[idx].str()); idx++; { auto num = tokens[idx].str(); if(tokens[idx] != TT::Number || num.find('.') != std::string::npos) expected(tokens[idx].loc, "integer value for precedence", num); int prec = std::stoi(num); if(prec <= 0) expected(tokens[idx].loc, "a precedence value greater than zero", num); oper.precedence = prec; idx++; } if(tokens[idx] != TT::Comma) expected(tokens[idx].loc, "',' in argument list to '@operator'", tokens[idx].str()); idx++; if(tokens[idx] != TT::UnicodeSymbol && tokens[idx] != TT::Identifier) { error(tokens[idx].loc, "custom operator symbol must be a unicode symbol or regular identifier, '%s' is invalid", tokens[idx].str()); } oper.symbol = tokens[idx].str(); idx++; if(tokens[idx] != TT::RSquare) error(tokens[idx].loc, "expected ']' to terminate operator declaration, found '%s'", tokens[idx].str()); idx++; if(_kind) *_kind = kind; if(out) *out = oper; return idx; } std::tuple, util::hash_map, util::hash_map> parseOperators(const lexer::TokenList& tokens) { using Token = lexer::Token; using TT = lexer::TokenType; util::hash_map infix; util::hash_map prefix; util::hash_map postfix; // basically, this is how it goes: // only allow comments to occur before imports // all imports must happen before anything else in the file // comments can be interspersed between import statements, of course. for(size_t i = 0; i < tokens.size(); i++) { const Token& tok = tokens[i]; if(tok == TT::Attr_Operator) { CustomOperatorDecl oper; int kind = 0; i = parseOperatorDecl(tokens, i, &kind, &oper); if(kind == 1) infix[oper.symbol] = oper; else if(kind == 2) prefix[oper.symbol] = oper; else if(kind == 3) postfix[oper.symbol] = oper; } else if(tok == TT::Export || tok == TT::Import) { // skip until a newline. while(tokens[i] != TT::Comment && tokens[i] != TT::NewLine) i++; } else if(tok == TT::Comment || tok == TT::NewLine) { // skipped } else { // stop imports. break; } } return std::make_tuple(infix, prefix, postfix); } } namespace Operator { const std::string Plus = "+"; const std::string Minus = "-"; const std::string Multiply = "*"; const std::string Divide = "/"; const std::string Modulo = "%"; const std::string UnaryPlus = "+"; const std::string UnaryMinus = "-"; const std::string PointerDeref = "*"; const std::string AddressOf = "&"; const std::string BitwiseNot = "~"; const std::string BitwiseAnd = "&"; const std::string BitwiseOr = "|"; const std::string BitwiseXor = "^"; const std::string BitwiseShiftLeft = "<<"; const std::string BitwiseShiftRight = ">>"; const std::string LogicalNot = "!"; const std::string LogicalAnd = "&&"; const std::string LogicalOr = "||"; const std::string CompareEQ = "=="; const std::string CompareNEQ = "!="; const std::string CompareLT = "<"; const std::string CompareLEQ = "<="; const std::string CompareGT = ">"; const std::string CompareGEQ = ">="; const std::string Assign = "="; const std::string PlusEquals = "+="; const std::string MinusEquals = "-="; const std::string MultiplyEquals = "*="; const std::string DivideEquals = "/="; const std::string ModuloEquals = "%="; const std::string BitwiseShiftLeftEquals = "<<="; const std::string BitwiseShiftRightEquals = ">>="; const std::string BitwiseXorEquals = "^="; const std::string BitwiseAndEquals = "&="; const std::string BitwiseOrEquals = "|="; const std::string TypeCast = "as"; const std::string TypeIs = "is"; bool isArithmetic(const std::string& op) { return (op == Operator::Plus || op == Operator::Minus || op == Operator::Multiply || op == Operator::Divide || op == Operator::Modulo); } bool isBitwise(const std::string& op) { return (op == Operator::BitwiseAnd || op == Operator::BitwiseOr || op == Operator::BitwiseXor || op == Operator::BitwiseShiftLeft || op == Operator::BitwiseShiftRight); } bool isAssignment(const std::string& op) { return (op == Operator::Assign || op == Operator::PlusEquals || op == Operator::MinusEquals || op == Operator::MultiplyEquals || op == Operator::DivideEquals || op == Operator::ModuloEquals || op == Operator::BitwiseShiftLeftEquals || op == Operator::BitwiseShiftRightEquals || op == Operator::BitwiseAndEquals || op == Operator::BitwiseOrEquals || op == Operator::BitwiseXorEquals); } bool isComparison(const std::string& op) { return (op == Operator::CompareEQ || op == Operator::CompareNEQ || op == Operator::CompareLT || op == Operator::CompareGT || op == Operator::CompareLEQ || op == Operator::CompareGEQ); } std::string getNonAssignmentVersion(const std::string& op) { if(op == Operator::PlusEquals) return Operator::Plus; else if(op == Operator::MinusEquals) return Operator::Minus; else if(op == Operator::MultiplyEquals) return Operator::Multiply; else if(op == Operator::DivideEquals) return Operator::Divide; else if(op == Operator::ModuloEquals) return Operator::Modulo; else if(op == Operator::BitwiseShiftLeftEquals) return Operator::BitwiseShiftLeft; else if(op == Operator::BitwiseShiftRightEquals) return Operator::BitwiseShiftRight; else if(op == Operator::BitwiseAndEquals) return Operator::BitwiseAnd; else if(op == Operator::BitwiseOrEquals) return Operator::BitwiseOr; else if(op == Operator::BitwiseXorEquals) return Operator::BitwiseXor; error("no"); } } ================================================ FILE: source/frontend/parser/toplevel.cpp ================================================ // toplevel.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "defs.h" #include "pts.h" #include "errors.h" #include "parser.h" #include "frontend.h" #include "parser_internal.h" #include "memorypool.h" using namespace lexer; using namespace ast; namespace parser { std::pair> parseIdentPath(const lexer::TokenList& tokens, size_t* idx) { using TT = lexer::TokenType; std::vector path; size_t i = *idx; Location loc = tokens[i].loc; while(tokens[i] == TT::Identifier) { loc = loc.unionWith(tokens[i].loc); path.push_back(tokens[i].str()); i++; if(tokens[i] == TT::DoubleColon) { i++; if(tokens[i] != TT::Identifier) expectedAfter(tokens[i - 1].loc, "identifier", "'::' in path", tokens[i].str()); } else { break; } } *idx = i; return { loc, path }; } static std::pair> parseModuleName(const std::string& fullname, const frontend::FileInnards& fileinnards) { using TT = lexer::TokenType; const auto& tokens = fileinnards.tokens; std::vector path; // basically, this is how it goes: // only allow comments to occur before the module name. for(size_t i = 0; i < tokens.size(); i++) { const Token& tok = tokens[i]; if(tok.type == TT::Export) { i++; if(tokens[i].type == TT::Identifier) { path = parseIdentPath(tokens, &i).second; } else { expectedAfter(tokens[i].loc, "identifier for export declaration", "'module'", tokens[i].str()); } if(tokens[i].type != TT::NewLine && tokens[i].type != TT::Semicolon && tokens[i].type != TT::Comment) { expected(tokens[i].loc, "newline or semicolon to terminate export statement", tokens[i].str()); } // i++ handled by loop } else if(tok.type == TT::Comment || tok.type == TT::NewLine) { // skipped } else { // stop break; } } if(path.empty()) path = { frontend::removeExtensionFromFilename(frontend::getFilenameFromPath(fullname)) }; return { path.back(), zfu::take(path, path.size() - 1) }; } TopLevelBlock* parseTopLevel(State& st, const std::string& name) { using TT = lexer::TokenType; TopLevelBlock* root = util::pool(st.loc(), name); // if it's not empty, then it's an actual user-defined namespace bool hadLBrace = false; if(name != "") { // expect "namespace FOO { ... }" hadLBrace = true; iceAssert(st.front() == TT::Identifier); st.eat(); if(st.eat() != TT::LBrace) expected(st.ploc(), "'{' to start namespace declaration", st.prev().str()); } bool isFirst = true; auto priv = VisibilityLevel::Invalid; size_t tix = static_cast(-1); while(st.hasTokens() && st.front() != TT::EndOfFile) { switch(st.front()) { case TT::Import: { if(name != "" || !st.importsStillValid) error(st, "import statements are not allowed here"); root->statements.push_back(parseImport(st)); } break; case TT::Attr_Operator: { if(name != "" || !st.operatorsStillValid) error(st, "custom operator declarations are not allowed here"); // just skip it. st.setIndex(parseOperatorDecl(st.getTokenList(), st.getIndex(), 0, 0)); st.importsStillValid = false; st.nativeWordSizeStillValid = false; } break; case TT::Attr_Platform: { auto ret = parsePlatformDefn(st); if(ret) // sometimes we set a setting, but it doesn't need to have an AST node. root->statements.push_back(ret); st.importsStillValid = false; st.nativeWordSizeStillValid = false; } break; case TT::Namespace: { st.eat(); Token tok = st.front(); if(tok != TT::Identifier) expectedAfter(st, "identifier", "'namespace'", st.front().str()); auto ns = parseTopLevel(st, tok.str()); if(priv != VisibilityLevel::Invalid) { ns->visibility = priv; priv = VisibilityLevel::Invalid; tix = static_cast(-1); } root->statements.push_back(ns); st.importsStillValid = false; st.operatorsStillValid = false; st.nativeWordSizeStillValid = false; } break; case TT::Attr_NoMangle: { st.pop(); auto stmt = parseStmt(st).val(); if(!dcast(FuncDefn, stmt) && !dcast(VarDefn, stmt)) error(st, "attribute '@nomangle' can only be applied on function and variable declarations"); else if(dcast(ForeignFuncDefn, stmt)) warn(st, "attribute '@nomangle' is redundant on 'ffi' functions"); else if(auto fd = dcast(FuncDefn, stmt)) fd->attrs.set(attr::NO_MANGLE); else if(auto vd = dcast(VarDefn, stmt)) vd->attrs.set(attr::NO_MANGLE); root->statements.push_back(stmt); st.importsStillValid = false; st.operatorsStillValid = false; st.nativeWordSizeStillValid = false; } break; case TT::Attr_EntryFn: { st.pop(); auto stmt = parseStmt(st).val(); if(auto fd = dcast(FuncDefn, stmt)) fd->attrs.set(attr::FN_ENTRYPOINT); else error(st, "'@entry' attribute is only applicable to function definitions"); root->statements.push_back(stmt); st.importsStillValid = false; st.operatorsStillValid = false; st.nativeWordSizeStillValid = false; } break; case TT::Public: priv = VisibilityLevel::Public; tix = st.getIndex(); st.pop(); break; case TT::Private: priv = VisibilityLevel::Private; tix = st.getIndex(); st.pop(); break; case TT::Internal: priv = VisibilityLevel::Internal; tix = st.getIndex(); st.pop(); break; case TT::Comment: case TT::NewLine: isFirst = true; st.skipWS(); continue; case TT::RBrace: if(!hadLBrace) error(st, "unexpected '}'"); goto out; default: { if(priv != VisibilityLevel::Invalid) { st.rewindTo(tix); tix = static_cast(-1); priv = VisibilityLevel::Invalid; } if(st.front() == TT::Export) { if(!isFirst || name != "") { error(st, "export declaration not allowed here (%s / %d)", name, isFirst); } else { st.eat(); size_t i = st.getIndex(); parseIdentPath(st.getTokenList(), &i); st.setIndex(i); break; } } st.importsStillValid = false; st.operatorsStillValid = false; st.nativeWordSizeStillValid = false; root->statements.push_back(parseStmt(st, /* allowExprs: */ false).val()); } break; } isFirst = false; st.skipWS(); } out: if(name != "") { if(st.front() != TT::RBrace) expected(st, "'}' to close namespace declaration", st.front().str()); st.eat(); } // throw in all anonymous types to the top level root->statements.insert(root->statements.begin(), st.anonymousTypeDefns.begin(), st.anonymousTypeDefns.end()); return root; } ParsedFile parseFile(const std::string& fullname, const frontend::FileInnards& file, frontend::CollectorState& cs) { const TokenList& tokens = file.tokens; auto state = State(tokens); state.currentFilePath = fullname; // copy this stuff over. state.binaryOps = cs.binaryOps; state.prefixOps = cs.prefixOps; state.postfixOps = cs.postfixOps; state.cState = &cs; auto [ modname, modpath ] = parseModuleName(fullname, file); auto toplevel = parseTopLevel(state, ""); return ParsedFile { fullname, modname, modpath, toplevel, }; } } ================================================ FILE: source/frontend/parser/type.cpp ================================================ // type.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "pts.h" #include "parser_internal.h" #include "memorypool.h" using namespace ast; using namespace lexer; // defined in fir/name.cpp namespace fir { std::string obfuscateName(const std::string& name, size_t id); } namespace parser { using TT = lexer::TokenType; template static void addSelfToMethod(T* thing, bool mutating) { // insert the self argument in the front. FuncDefn::Param self; self.name = "this"; self.loc = thing->loc; self.type = util::pool(self.loc, pts::NamedType::create(self.loc, "self"), mutating); thing->params.insert(thing->params.begin(), self); } ClassDefn* parseClass(State& st) { iceAssert(st.front() == TT::Class); st.eat(); if(st.front() != TT::Identifier) expectedAfter(st, "identifier", "'struct'", st.front().str()); ClassDefn* defn = util::pool(st.loc()); defn->name = st.eat().str(); // check for generic function if(st.front() == TT::LAngle) { st.eat(); // parse generic if(st.front() == TT::RAngle) error(st, "empty type parameter lists are not allowed"); defn->generics = parseGenericTypeList(st); } st.skipWS(); if(st.front() == TT::Colon) { // the inheritance list. st.eat(); while(true) { defn->bases.push_back(parseType(st)); if(st.front() == TT::Comma) { st.pop(); continue; } else { break; } } } st.skipWS(); if(st.front() != TT::LBrace) expectedAfter(st, "'{'", "'class'", st.front().str()); st.enterStructBody(); auto blk = parseBracedBlock(st).val(); for(auto s : blk->statements) { if(auto v = dcast(VarDefn, s)) { if(v->type == pts::InferredType::get()) error(v, "class fields must have types explicitly specified"); v->isField = true; defn->fields.push_back(v); } else if(auto f = dcast(FuncDefn, s)) { addSelfToMethod(f, f->isMutating); defn->methods.push_back(f); } else if(auto t = dcast(TypeDefn, s)) { defn->nestedTypes.push_back(t); } else if(auto sd = dcast(StaticDecl, s)) { if(auto fn = dcast(FuncDefn, sd->actual)) defn->staticMethods.push_back(fn); else if(auto vr = dcast(VarDefn, sd->actual)) defn->staticFields.push_back(vr); else error(st, "unsupported static statement in class body"); } else if(auto init = dcast(InitFunctionDefn, s)) { addSelfToMethod(init, /* mutating: */ true); if(init->name == "init") { defn->initialisers.push_back(init); } else if(init->name == "deinit") { if(defn->deinitialiser) error(init, "deinitialisers cannot be overloaded"); defn->deinitialiser = init; } else if(init->name == "copy") { if(defn->copyInitialiser) error(init, "copy initialisers cannot be overloaded"); defn->copyInitialiser = init; } else if(init->name == "move") { if(defn->moveInitialiser) error(init, "move initialisers cannot be overloaded"); defn->moveInitialiser = init; } else { error(s, "wtf? '%s'", init->name); } } else { error(s, "unsupported expression or statement in class body"); } } if(!blk->deferredStatements.empty()) error(blk->deferredStatements[0], "unsupported expression or statement in class body"); st.leaveStructBody(); return defn; } PResult parseStruct(State& st, bool nameless) { static size_t anon_counter = 0; iceAssert(st.front() == TT::Struct); st.eat(); StructDefn* defn = util::pool(st.loc()); if(nameless) { defn->name = fir::obfuscateName("anon_struct", anon_counter++); } else { if(st.front() == TT::LBrace) error(st, "declared structs (in non-type usage) must be named"); else if(st.front() != TT::Identifier) expectedAfter(st, "identifier", "'struct'", st.front().str()); else defn->name = st.eat().str(); } // check for generic function if(st.front() == TT::LAngle) { st.eat(); // parse generic if(st.front() == TT::RAngle) error(st, "empty type parameter lists are not allowed"); defn->generics = parseGenericTypeList(st); } st.skipWS(); if(st.front() == TT::Colon) { // the inheritance list. st.eat(); while(true) { defn->bases.push_back(parseType(st)); if(st.front() == TT::Comma) { st.pop(); continue; } else { break; } } } st.skipWS(); if(st.eat() != TT::LBrace) expectedAfter(st.ploc(), "opening brace", "'struct'", st.front().str()); st.enterStructBody(); st.skipWS(); size_t index = 0; while(st.front() != TT::RBrace) { st.skipWS(); if(!st.hasTokens()) return PResult::insufficientTokensError(); if(st.front() == TT::Identifier) { auto loc = st.loc(); std::string name = st.eat().str(); // we can't check for duplicates when it's transparent, duh // we'll collapse and collect and check during typechecking. if(name != "_") { if(auto it = std::find_if(defn->fields.begin(), defn->fields.end(), [&name](const auto& p) -> bool { return std::get<0>(p) == name; }); it != defn->fields.end()) { SimpleError::make(loc, "duplicate field '%s' in struct definition", name) ->append(SimpleError::make(MsgType::Note, std::get<1>(*it), "field '%s' previously defined here:", name)) ->postAndQuit(); } } if(st.eat() != TT::Colon) error(st.ploc(), "expected type specifier after field name in struct"); pts::Type* type = parseType(st); defn->fields.push_back(std::make_tuple(name, loc, type)); if(st.front() == TT::Equal) error(st.loc(), "struct fields cannot have initialisers"); } else if(st.front() == TT::Func) { // ok parse a func as usual auto method = parseFunction(st).val(); addSelfToMethod(method, method->isMutating); defn->methods.push_back(method); } else if(st.front() == TT::Var || st.front() == TT::Val) { error(st.loc(), "struct fields are declared as 'name: type'; val/let is omitted"); } else if(st.front() == TT::Static) { error(st.loc(), "structs cannot have static declarations"); } else if(st.front() == TT::NewLine || st.front() == TT::Semicolon) { st.pop(); } else if(st.front() == TT::RBrace) { break; } else { error(st.loc(), "unexpected token '%s' (%d) inside struct body", st.front().str(), st.front().type); } index++; } iceAssert(st.front() == TT::RBrace); st.eat(); st.leaveStructBody(); return defn; } UnionDefn* parseUnion(State& st, bool israw, bool nameless) { static size_t anon_counter = 0; iceAssert(st.front() == TT::Union); st.eat(); UnionDefn* defn = util::pool(st.loc()); if(nameless) { defn->name = fir::obfuscateName("anon_union", anon_counter++); } else { if(st.front() == TT::LBrace) error(st, "declared unions (in non-type usage) must be named"); else if(st.front() != TT::Identifier) expectedAfter(st, "identifier", "'union'", st.front().str()); else defn->name = st.eat().str(); } // check for generic function if(st.front() == TT::LAngle) { st.eat(); // parse generic if(st.front() == TT::RAngle) error(st, "empty type parameter lists are not allowed"); defn->generics = parseGenericTypeList(st); } // unions don't inherit stuff (for now????) so we don't check for it. st.skipWS(); if(st.eat() != TT::LBrace) expectedAfter(st.ploc(), "opening brace", "'union'", st.front().str()); st.skipWS(); if(st.front() == TT::RBrace) error(st, "union must contain at least one variant"); size_t index = 0; while(st.front() != TT::RBrace) { st.skipWS(); if(st.front() != TT::Identifier) { if(st.front() == TT::Var || st.front() == TT::Val) error(st.loc(), "union fields are declared as 'name: type'; val/let is omitted"); else expected(st.loc(), "identifier inside union body", st.front().str()); } auto loc = st.loc(); pts::Type* type = 0; std::string name = st.eat().str(); // to improve code flow, handle the type first. if(st.front() == TT::Colon) { st.eat(); type = parseType(st); } else { if(israw) error(st.loc(), "raw unions cannot have empty variants (must have a type)"); else if(st.front() != TT::NewLine) error(st.loc(), "expected newline after union variant"); } if(name == "_") { if(!israw) error(loc, "transparent fields can only be present in raw unions"); iceAssert(type); defn->transparentFields.push_back({ loc, type }); } else { if(auto it = defn->cases.find(name); it != defn->cases.end()) { SimpleError::make(loc, "duplicate variant '%s' in union definition", name) ->append(SimpleError::make(MsgType::Note, std::get<1>(it->second), "variant '%s' previously defined here:", name)) ->postAndQuit(); } if(type == nullptr) type = pts::NamedType::create(loc, VOID_TYPE_STRING); defn->cases[name] = { index, loc, type }; } // do some things if(st.front() == TT::NewLine || st.front() == TT::Semicolon) { st.pop(); } else if(st.front() == TT::RBrace) { break; } else { error(st.loc(), "unexpected token '%s' inside union body", st.front().str()); } index++; } iceAssert(st.front() == TT::RBrace); st.eat(); if(israw) defn->attrs.set(attr::RAW); return defn; } EnumDefn* parseEnum(State& st) { iceAssert(st.front() == TT::Enum); st.eat(); if(st.front() != TT::Identifier) expectedAfter(st, "identifier", "'enum'", st.front().str()); auto idloc = st.loc(); std::string name = st.eat().str(); pts::Type* memberType = 0; if(st.front() == TT::Colon) { st.eat(); memberType = parseType(st); } // ok... st.skipWS(); if(st.eat() != TT::LBrace) expectedAfter(st.ploc(), "opening brace", "'enum'", st.front().str()); bool hadValue = false; std::vector cases; while(st.front() != TT::RBrace) { st.skipWS(); if(st.front() == TT::RBrace) break; if(st.eat() != TT::Case) expected(st.ploc(), "'case' inside enum body", st.prev().str()); if(st.front() != TT::Identifier) expectedAfter(st.loc(), "identifier", "'case' in enum body", st.front().str()); std::string cn = st.eat().str(); Expr* value = 0; if(st.frontAfterWS() == TT::Equal) { if(memberType == 0) { SimpleError::make(st.loc(), "enumeration member type must be specified when assigning explicit values to cases") ->append(SimpleError::make(MsgType::Note, idloc, "add the type here")) ->postAndQuit(); } // ok, parse a value st.eat(); value = parseExpr(st); hadValue = true; } else if(hadValue) { //? this is mostly because we don't want to deal with auto-incrementing stuff error(st.loc(), "enumeration cases must either all have no values, or all have values; a mix is not allowed."); } // ok. cases.push_back(EnumDefn::Case { st.loc(), cn, value }); // do some things if(st.front() == TT::NewLine || st.front() == TT::Semicolon) { st.pop(); } else if(st.front() == TT::RBrace) { break; } else { error(st.loc(), "unexpected token '%s' inside enum body", st.front().str()); } } iceAssert(st.front() == TT::RBrace); st.eat(); auto ret = util::pool(idloc); ret->name = name; ret->cases = cases; ret->memberType = memberType; return ret; } TraitDefn* parseTrait(State& st) { iceAssert(st.front() == TT::Trait); st.eat(); if(st.front() != TT::Identifier) expectedAfter(st, "identifier", "'trait'", st.front().str()); TraitDefn* defn = util::pool(st.loc()); defn->name = st.eat().str(); st.skipWS(); if(st.front() == TT::Colon) { // the inheritance list. st.eat(); while(true) { defn->bases.push_back(parseType(st)); if(st.front() == TT::Comma) { st.pop(); continue; } else { break; } } } // ok... st.skipWS(); if(st.eat() != TT::LBrace) expectedAfter(st.ploc(), "opening brace", "'trait'", st.front().str()); st.enterStructBody(); st.skipWS(); size_t index = 0; while(st.front() != TT::RBrace) { st.skipWS(); if(st.front() == TT::Func) { // ok parse a func as usual auto [ method, isvar, varloc ] = parseFunctionDecl(st); if(isvar) error(varloc, "C-style variadic arguments are not supported on non-foreign functions"); addSelfToMethod(method, method->isMutating); defn->methods.push_back(method); } else if(st.front() == TT::Var || st.front() == TT::Val) { error(st.loc(), "traits cannot contain fields"); } else if(st.front() == TT::Static) { error(st.loc(), "traits cannot contain static declarations"); } else if(st.front() == TT::NewLine || st.front() == TT::Semicolon) { st.pop(); } else if(st.front() == TT::RBrace) { break; } else { error(st.loc(), "unexpected token '%s' inside trait body", st.front().str()); } index++; } iceAssert(st.front() == TT::RBrace); st.eat(); st.leaveStructBody(); return defn; } StaticDecl* parseStaticDecl(State& st) { iceAssert(st.front() == TT::Static); st.eat(); auto stmt = parseStmt(st).val(); if(dcast(FuncDefn, stmt) || dcast(VarDefn, stmt)) return util::pool(stmt); else error(stmt, "'static' can only be used on function and field definitions inside class bodies"); } pts::Type* parseType(State& st) { using TT = lexer::TokenType; if(st.front() == TT::Ampersand) { auto l = st.loc(); st.pop(); // check for mutability. bool mut = st.front() == TT::Mutable; if(mut) st.pop(); auto base = parseType(st); l.len = base->loc.col - l.col + base->loc.len; return util::pool(l, base, mut); } else if(st.front() == TT::LogicalAnd) { // lmao. auto l = st.loc(); st.pop(); bool mut = st.front() == TT::Mutable; if(mut) st.pop(); //* note: this handles cases like & (&mut T) //* so, the outer pointer is never mutable, but the inner one might be. auto base = parseType(st); l.len = base->loc.col - l.col + base->loc.len; return util::pool(l, util::pool(l, base, mut), false); } else if(st.front() == TT::LSquare) { // [T] is a dynamic array // [T:] is a slice // [T: N] is a fixed array of size 'N' auto loc = st.loc(); st.pop(); bool mut = false; if(st.front() == TT::Mutable) mut = true, st.pop(); auto elm = parseType(st); if(st.front() == TT::Colon) { st.pop(); if(st.front() == TT::RSquare) { loc.len = st.loc().col - loc.col + st.loc().len; st.pop(); return util::pool(loc, elm, mut); } else if(st.front() == TT::Ellipsis) { st.pop(); loc.len = st.loc().col - loc.col + st.loc().len; if(st.pop() != TT::RSquare) expectedAfter(st, "']'", "... in variadic array type", st.front().str()); return util::pool(loc, elm); } else if(st.front() != TT::Number) { expected(st, "positive, non-zero size for fixed array", st.front().str()); } else { long sz = std::stol(st.front().str()); if(sz <= 0) expected(st, "positive, non-zero size for fixed array", st.front().str()); st.pop(); loc.len = st.loc().col - loc.col + st.loc().len; if(st.eat() != TT::RSquare) expectedAfter(st, "closing ']'", "array type", st.front().str()); //! ACHTUNG ! // TODO: support mutable arrays?? return util::pool(loc, elm, sz); } } else if(st.front() == TT::RSquare) { // dynamic array. if(mut) error(st.loc(), "dynamic arrays are always mutable, specifying 'mut' is unnecessary"); loc.len = st.loc().col - loc.col + st.loc().len; st.pop(); return util::pool(loc, elm); } else { expected(st.loc(), "']' in array type specifier", st.front().str()); } } else if(st.front() == TT::Identifier || st.front() == TT::DoubleColon || st.front() == TT::Caret) { if(st.front() == TT::Caret && st.lookahead(1) != TT::DoubleColon) error(st, "'^' in type specifier must be followed by '::' (to specify parent scope)"); auto loc = st.loc(); std::string s = st.eat().str(); while(st.hasTokens()) { if(st.front() == TT::DoubleColon) { s += st.eat().str(); } else if(st.front() == TT::Caret) { s += st.eat().str(); if(st.front() != TT::DoubleColon) error(st, "expected '::' after '^' in scope path"); } else if(st.front() == TT::Identifier) { if(s.back() != ':') error(st, "unexpected identifer '%s' in type", st.front().str()); else s += st.eat().str(); } else { break; } } // check generic mapping PolyArgMapping_t pams; if(st.front() == TT::Exclamation && st.lookahead(1) == TT::LAngle) { //? note: if *failed is nullptr, then we will throw errors where we usually would return. pams = parsePAMs(st, /* fail: */ nullptr); } loc.len = st.ploc().col - loc.col + st.ploc().len; return pts::NamedType::create(loc, s, pams); } else if(auto isfn = (st.front() == TT::Func); st.front() == TT::LParen || st.front() == TT::Func) { // tuple or function auto loc = st.loc(); st.pop(); if(isfn) st.pop(); // parse a tuple. std::vector types; while(st.hasTokens() && st.front().type != TT::RParen) { // do things. auto ty = parseType(st); if(st.front() != TT::Comma && st.front() != TT::RParen) error(st, "unexpected token '%s' in type specifier, expected either ',' or ')'", st.front().str()); else if(st.front() == TT::Comma) st.eat(); types.push_back(ty); } loc.len = st.loc().col - loc.col + st.loc().len; if(st.eat().type != TT::RParen) expected(st, "')' to end type list", st.prev().str()); if(isfn) { if(st.front() != TT::RightArrow) expected(st, "'->' in function type specifier after parameter types", st.front().str()); st.eat(); // eat the arrow, parse the type auto retty = parseType(st); loc.len = st.ploc().col - loc.col + st.ploc().len; return util::pool(loc, types, retty); } else { // this *should* allow us to 'group' types together // eg. ((i64, i64) -> i64)[] would allow us to create an array of functions // whereas (i64, i64) -> i64[] would parse as a function returning an array of i64s. if(types.size() == 0) error(st, "empty tuples '()' are not supported"); else if(types.size() == 1) return types[0]; return util::pool(loc, types); } } else if(st.front() == TT::Struct) { auto str = parseStruct(st, /* nameless: */ true).val(); st.anonymousTypeDefns.push_back(str); return pts::NamedType::create(str->loc, str->name); } else if(st.front() == TT::Union || (st.front() == TT::Attr_Raw && st.lookahead(1) == TT::Union)) { bool israw = st.front() == TT::Attr_Raw; if(israw) st.eat(); auto unn = parseUnion(st, israw, /* nameless: */ true); st.anonymousTypeDefns.push_back(unn); return pts::NamedType::create(unn->loc, unn->name); } else if(st.front() == TT::Class) { error(st, "classes cannot be defined anonymously"); } else { error(st, "unexpected token '%s' while parsing type", st.front().str()); } } // PAM == PolyArgMapping PolyArgMapping_t parsePAMs(State& st, bool* failed) { iceAssert(st.front() == TT::Exclamation && st.lookahead(1) == TT::LAngle); auto openLoc = st.loc(); st.pop(); st.pop(); std::unordered_set seen; PolyArgMapping_t mappings; { //* foo!<> is an error regardless of whether we're doing expression parsing or call parsing. if(st.front() == TT::RAngle) error(Location::unionOf(openLoc, st.loc()), "type parameter list cannot be empty"); // step 2A: start parsing. size_t idx = 0; while(st.front() != TT::RAngle) { if(st.front() != TT::Identifier) { if(failed) { *failed = true; return mappings; } else { expected(st.loc(), "identifier in type argument list", st.front().str()); } } if(st.front() == TT::Identifier && st.lookahead(1) == TT::Colon) { auto id = st.pop().str(); st.pop(); //? I think beyond this point we pretty much can't fail since we have the colon. //? so, we shouldn't need to handle the case where we fail to parse a type here. if(seen.find(id) != seen.end()) error(st.loc(), "duplicate type argument '%s'", id); auto ty = parseType(st); mappings.add(id, ty); seen.insert(id); } else { if(!seen.empty()) error(st.loc(), "cannot have positional type arguments after named arguments"); auto ty = parseType(st); mappings.add(idx++, ty); } if(st.front() == TT::Comma) st.pop(); else if(st.front() != TT::RAngle) expected(st.loc(), "',' or '>' in type argument list", st.front().str()); } iceAssert(st.front() == TT::RAngle); st.pop(); return mappings; } } } ================================================ FILE: source/frontend/parser/variable.cpp ================================================ // variable.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "pts.h" #include "parser_internal.h" #include "memorypool.h" #include using namespace ast; using namespace lexer; namespace parser { static DecompMapping recursivelyParseDecomp(State& st) { using TT = lexer::TokenType; DecompMapping outer; outer.loc = st.loc(); iceAssert(st.front() == TT::LSquare || st.front() == TT::LParen); if(st.pop() == TT::LSquare) outer.array = true; bool didRest = false; while(st.front() != (outer.array ? TT::RSquare : TT::RParen)) { DecompMapping inside; inside.loc = st.loc(); if(st.front() == TT::Ampersand) inside.ref = true, st.pop(); if(st.front() == TT::LParen || st.front() == TT::LSquare) { if(inside.ref) error(st, "cannot bind by reference in nested decomposition; modify the binding type for each identifier"); outer.inner.push_back(recursivelyParseDecomp(st)); } else if(st.front() == TT::Ellipsis) { if(!outer.array) error(st, "'...' cannot be used in a tuple destructure"); else if(didRest) error(st, "'...' must be the last binding in an array destructure"); else if(inside.ref) error(st, "invalid use of '&' before '...' binding"); st.pop(); if(st.front() == TT::Ampersand) outer.restRef = true, st.pop(); if(st.front() == TT::Identifier) outer.restName = st.front().str(), st.pop(); if(outer.restName == "_" && outer.restRef) error(st.ploc(), "invalid combination of '_' and '&'"); didRest = true; } else if(st.front() == TT::Identifier) { inside.name = st.pop().str(); if(inside.name == "_" && inside.ref) error(st.loc(), "invalid combination of '_' and '&'"); outer.inner.push_back(inside); } else { expected(st.loc(), "identifier or '...' in destructuring declaration", st.front().str()); } if(st.front() != TT::Comma && st.front() != (outer.array ? TT::RSquare : TT::RParen)) expected(st, "')', ']' or ',' in destructuring declaration", st.front().str()); if(st.front() == TT::Comma) st.pop(); } if(outer.array && !didRest) error(st, "'...' is mandatory for array destructuring, regardless of binding"); iceAssert(st.front() == (outer.array ? TT::RSquare : TT::RParen)); st.pop(); return outer; } DecompVarDefn* parseDecompDecl(State& st) { using TT = lexer::TokenType; iceAssert(st.front() == TT::LSquare || st.front() == TT::LParen); auto decomp = util::pool(st.loc()); decomp->bindings = recursivelyParseDecomp(st); // we need to ensure there're no duplicate names. std::function& names)> visit; visit = [&visit](const DecompMapping& dm, std::map& seen) -> void { if(!dm.name.empty() && dm.name != "_") { if(seen.find(dm.name) != seen.end()) { SimpleError::make(dm.loc, "duplicate binding '%s' in destructuring declaration", dm.name) ->append(SimpleError::make(MsgType::Note, seen[dm.name], "previous binding was here:")) ->postAndQuit(); } else { seen[dm.name] = dm.loc; } } else if(dm.name.empty()) { for(const auto& b : dm.inner) visit(b, seen); } }; std::map seen; visit(decomp->bindings, seen); if(st.front() != TT::Equal) expected(st, "'=' for assignment to decomposition", st.front().str()); st.pop(); decomp->initialiser = parseExpr(st); return decomp; } DecompMapping parseTupleDecomp(State& st) { return recursivelyParseDecomp(st); } Stmt* parseVariable(State& st) { using TT = lexer::TokenType; iceAssert(st.front() == TT::Var || st.front() == TT::Val); bool isImmut = (st.eat() == TT::Val); if(st.front() == TT::LParen || st.front() == TT::LSquare) { auto ret = parseDecompDecl(st); ret->immut = isImmut; return ret; } else if(st.front() != TT::Identifier) { expectedAfter(st, "identifier", "'" + std::string(isImmut ? "let" : "var") + "'", st.front().str()); } auto loc = st.front().loc; std::string name = st.eat().str(); pts::Type* type = pts::InferredType::get(); Expr* value = 0; if(st.front() == TT::Colon) { st.pop(); type = parseType(st); } else if(st.front() != TT::Equal) { error(st, "expected initial value for type inference on variable '%s'", name); } if(st.front() == TT::Equal) { st.pop(); value = parseExpr(st); } else if(isImmut) { error(st, "expected initial value for immutable variable '%s'", name); } auto ret = util::pool(loc); ret->initialiser = value; ret->immut = isImmut; ret->type = type; ret->name = name; return ret; } } ================================================ FILE: source/frontend/pts.cpp ================================================ // pts.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "pts.h" #include "memorypool.h" namespace pts { std::string unwrapPointerType(const std::string& type, int* _indirections) { std::string sptr = "*"; size_t ptrStrLength = sptr.length(); int tmp = 0; if(!_indirections) _indirections = &tmp; std::string actualType = type; if(actualType.length() > ptrStrLength && std::equal(sptr.rbegin(), sptr.rend(), actualType.rbegin())) { int& indirections = *_indirections; while(actualType.length() > ptrStrLength && std::equal(sptr.rbegin(), sptr.rend(), actualType.rbegin())) actualType = actualType.substr(0, actualType.length() - ptrStrLength), indirections++; } return actualType; } NamedType* Type::toNamedType() { return dcast(NamedType, this); } PointerType* Type::toPointerType() { return dcast(PointerType, this); } TupleType* Type::toTupleType() { return dcast(TupleType, this); } FixedArrayType* Type::toFixedArrayType() { return dcast(FixedArrayType, this); } DynamicArrayType* Type::toDynamicArrayType() { return dcast(DynamicArrayType, this); } VariadicArrayType* Type::toVariadicArrayType() { return dcast(VariadicArrayType, this); } FunctionType* Type::toFunctionType() { return dcast(FunctionType, this); } ArraySliceType* Type::toArraySliceType() { return dcast(ArraySliceType, this); } bool Type::isNamedType() { return dcast(NamedType, this) != 0; } bool Type::isPointerType() { return dcast(PointerType, this) != 0; } bool Type::isTupleType() { return dcast(TupleType, this) != 0; } bool Type::isFixedArrayType() { return dcast(FixedArrayType, this) != 0; } bool Type::isDynamicArrayType() { return dcast(DynamicArrayType, this) != 0; } bool Type::isVariadicArrayType() { return dcast(VariadicArrayType, this) != 0; } bool Type::isFunctionType() { return dcast(FunctionType, this) != 0; } bool Type::isArraySliceType() { return dcast(ArraySliceType, this) != 0; } std::string Type::str() { return "??"; } static InferredType* it = 0; InferredType* InferredType::get() { if(it) return it; return (it = util::pool(Location())); } NamedType* NamedType::create(const Location& l, const std::string& s) { return NamedType::create(l, s, { }); } NamedType* NamedType::create(const Location& l, const std::string& s, const PolyArgMapping_t& tm) { auto ret = util::pool(l, s); ret->genericMapping = tm; return ret; } // these shits are supposed to be reversibly-parse-able, so omit any "beautification" spaces and whatnot. std::string NamedType::str() { auto ret = this->name; if(!this->genericMapping.empty()) { std::string m; for(auto p : this->genericMapping.maps) m += strprintf("%s: %s, ", p.name.empty() ? std::to_string(p.index) : p.name, p.type->str()); if(this->genericMapping.maps.size() > 0) m.pop_back(), m.pop_back(); ret += "<" + m + ">"; } return ret; } std::string PointerType::str() { return (this->isMutable ? "&mut " : "&") + this->base->str(); } std::string TupleType::str() { std::string ret = "("; for(auto t : this->types) ret += t->str() + ", "; if(this->types.size() > 0) ret.pop_back(), ret.pop_back(); return ret + ")"; } std::string FixedArrayType::str() { std::string b = this->base->str(); if(this->base->isFunctionType()) b = "(" + b + ")"; return strprintf("[%s: %d]", b, std::to_string(this->size)); } std::string DynamicArrayType::str() { std::string b = this->base->str(); if(this->base->isFunctionType()) b = "(" + b + ")"; return strprintf("[%s]", b); } std::string VariadicArrayType::str() { std::string b = this->base->str(); if(this->base->isFunctionType()) b = "(" + b + ")"; return strprintf("[%s: ...]", b); } std::string ArraySliceType::str() { std::string b = this->base->str(); if(this->base->isFunctionType()) b = "(" + b + ")"; return strprintf("[%s:]", b); } std::string FunctionType::str() { std::string ret = "fn("; for(auto t : this->argTypes) ret += t->str() + ", "; if(this->argTypes.size() > 0) ret.pop_back(), ret.pop_back(); return ret + ") -> " + this->returnType->str(); } } ================================================ FILE: source/include/allocator.h ================================================ // allocator.h // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include #include namespace mem { void* allocate_memory(size_t bytes); void deallocate_memory(void* ptr, size_t bytes); size_t getAllocatedCount(); size_t getDeallocatedCount(); size_t getWatermark(); void resetStats(); } ================================================ FILE: source/include/ast.h ================================================ // ast.h // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include "defs.h" #include "sst_expr.h" #include "stcommon.h" #include "precompile.h" #include namespace pts { struct Type; } namespace fir { struct Type; } namespace sst { struct TypecheckState; struct FunctionDefn; struct FunctionDecl; } namespace ast { struct Stmt : Locatable { Stmt(const Location& l) : Locatable(l, "statement") { } virtual ~Stmt(); virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) = 0; AttribSet attrs; }; struct Expr : Stmt { Expr(const Location& l) : Stmt(l) { this->readableName = "expression"; } ~Expr(); virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) = 0; //? this flag is used in very specific cases (as of now [27/10/18] only for union variants), to tell the typecheck //? method to treat the expression as if it were evaluating a type, instead of trying to yield a value. //* specifically, ast::Ident uses this flag if it sees that its target is an sst::UnionVariantDefn; //* if checkAsType == true, it will target the VariantDefn; if checkAsType == false (as default), then //* it will make a UnionVariantConstructor instead. bool checkAsType = false; }; struct DeferredStmt : Stmt { DeferredStmt(const Location& l) : Stmt(l) { this->readableName = "deferred statement"; } ~DeferredStmt() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; Stmt* actual = 0; }; struct TypeDefn; struct Parameterisable : Stmt { Parameterisable(const Location& l) : Stmt(l) { this->readableName = ""; } ~Parameterisable() { } virtual std::string getKind() = 0; virtual TCResult generateDeclaration(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) = 0; virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) = 0; //* anything with generic abilities must implement the version of generateDeclaration and typecheck that accommodates the mapping argument //* if not we won't be able to know anything about anything. //? typecheck method is implemented for Parameterisable (and marked final) in typecheck/misc.cpp, where it simply calls the generic typecheck //? with an empty mapping. It is up to the individual AST during typechecking to verify `!gmaps.empty()` if `this->generics.size() > 0`. virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) final override; std::pair checkForExistingDeclaration(sst::TypecheckState* fs, const TypeParamMap_t& gmaps); std::string name; std::vector> generics; std::vector>> genericVersions; // kind of a hack. std::unordered_set finishedTypechecking; // another hack-y thing TypeDefn* parentType = 0; VisibilityLevel visibility = VisibilityLevel::Internal; // hacky thing #3 // explanation: the 'scope' of a type is always fixed, and it is the scope at the point of definition. // however, as we typecheck users of the type, our 'currentScope' moves around -- so we need to remember // the real, original scope of the type. //? we set this in typecheck/toplevel.cpp when generating the declarations. //? for methods & nested types, we set them in structs.cpp/classes.cpp //? in repl mode, we set this manually. sst::Scope enclosingScope; }; //* this does nothing!! struct ImportStmt : Stmt { ImportStmt(const Location& l) : Stmt(l) { this->readableName = "import statement"; } ~ImportStmt() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; }; struct Block : Stmt { Block(const Location& l) : Stmt(l) { this->readableName = "block"; } ~Block() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; Location closingBrace; bool doNotPushNewScope = false; bool isArrow = false; bool isFunctionBody = false; std::vector statements; std::vector deferredStatements; }; struct FuncDefn : Parameterisable { FuncDefn(const Location& l) : Parameterisable(l) { this->readableName = "function defintion"; } ~FuncDefn() { } virtual std::string getKind() override { return "function"; } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) override; virtual TCResult generateDeclaration(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) override; struct Param { std::string name; Location loc; pts::Type* type = 0; Expr* defaultValue = 0; }; std::vector params; pts::Type* returnType = 0; Block* body = 0; bool isMutating = false; bool isVirtual = false; bool isOverride = false; }; struct InitFunctionDefn : Parameterisable { InitFunctionDefn(const Location& l) : Parameterisable(l) { this->readableName = "class initialiser definition"; } ~InitFunctionDefn() { } virtual std::string getKind() override { return "initialiser"; } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) override; virtual TCResult generateDeclaration(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) override; using Param = FuncDefn::Param; std::vector params; bool didCallSuper = false; std::vector> superArgs; Block* body = 0; FuncDefn* actualDefn = 0; }; struct ForeignFuncDefn : Stmt { ForeignFuncDefn(const Location& l) : Stmt(l) { this->readableName = "foreign function definition"; } ~ForeignFuncDefn() { } sst::FunctionDecl* generatedDecl = 0; virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; using Param = FuncDefn::Param; std::string name; std::string realName; std::vector params; pts::Type* returnType = 0; bool isVarArg = false; bool isIntrinsic = false; //* note: foriegn functions are not Parameterisable, so they don't have the 'visibility' -- so we add it. VisibilityLevel visibility = VisibilityLevel::Internal; }; struct OperatorOverloadDefn : FuncDefn { OperatorOverloadDefn(const Location& l) : FuncDefn(l) { this->readableName = "operator overload defintion"; } ~OperatorOverloadDefn() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) override; virtual TCResult generateDeclaration(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) override; enum class Kind { Invalid, Infix, Prefix, Postfix }; std::string symbol; Kind kind = Kind::Invalid; }; struct VarDefn : Stmt { VarDefn(const Location& l) : Stmt(l) { this->readableName = "variable defintion"; } ~VarDefn() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; std::string name; pts::Type* type = 0; bool immut = false; Expr* initialiser = 0; bool isField = false; //* note: foriegn functions are not Parameterisable, so they don't have the 'visibility' -- so we add it. VisibilityLevel visibility = VisibilityLevel::Internal; bool noMangle = false; }; struct DecompVarDefn : Stmt { DecompVarDefn(const Location& l) : Stmt(l) { this->readableName = "destructuring variable defintion"; } ~DecompVarDefn() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; bool immut = false; Expr* initialiser = 0; DecompMapping bindings; }; struct PlatformDefn : Stmt { PlatformDefn(const Location& l) : Stmt(l) { this->readableName = "platform-specific definition"; } ~PlatformDefn() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; enum class Type { Invalid, Intrinsic, IntegerType }; Type defnType = Type::Invalid; // only valid if defnType == Intrinsic ForeignFuncDefn* intrinsicDefn = 0; // only valid if defnType == IntegerType std::string typeName; size_t typeSizeInBits = 0; }; struct IfStmt : Stmt { IfStmt(const Location& l) : Stmt(l) { this->readableName = "if statement"; } ~IfStmt() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; struct Case { Expr* cond = 0; Block* body = 0; std::vector inits; }; std::vector cases; Block* elseCase = 0; }; struct ReturnStmt : Stmt { ReturnStmt(const Location& l) : Stmt(l) { this->readableName = "return statement"; } ~ReturnStmt() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; Expr* value = 0; }; struct WhileLoop : Stmt { WhileLoop(const Location& l) : Stmt(l) { this->readableName = "while loop"; } ~WhileLoop() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; Expr* cond = 0; Block* body = 0; bool isDoVariant = false; }; struct ForLoop : Stmt { ForLoop(const Location& l) : Stmt(l) { this->readableName = "for loop"; } ~ForLoop() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override = 0; Block* body = 0; }; struct ForeachLoop : ForLoop { ForeachLoop(const Location& l) : ForLoop(l) { this->readableName = "for loop"; } ~ForeachLoop() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; Expr* array = 0; std::string indexVar; DecompMapping bindings; }; struct BreakStmt : Stmt { BreakStmt(const Location& l) : Stmt(l) { this->readableName = "break statement"; } ~BreakStmt() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; }; struct ContinueStmt : Stmt { ContinueStmt(const Location& l) : Stmt(l) { this->readableName = "continue statement"; } ~ContinueStmt() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; }; struct UsingStmt : Stmt { UsingStmt(const Location& l) : Stmt(l) { this->readableName = "using statement"; } ~UsingStmt() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; Expr* expr = 0; std::string useAs; }; struct StaticDecl : Stmt { StaticDecl(Stmt* s) : Stmt(s->loc), actual(s) { this->readableName = "static declaration"; } ~StaticDecl() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* inf = 0) override { return this->actual->typecheck(fs, inf); } Stmt* actual = 0; }; struct VirtualDecl : Stmt { VirtualDecl(Stmt* s) : Stmt(s->loc), actual(s) { this->readableName = "virtual declaration"; } ~VirtualDecl() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* inf = 0) override { return this->actual->typecheck(fs, inf); } Stmt* actual = 0; bool isOverride = false; }; struct TypeDefn : Parameterisable { TypeDefn(const Location& l) : Parameterisable(l) { this->readableName = "type definition"; } ~TypeDefn() { } }; struct StructDefn : TypeDefn { StructDefn(const Location& l) : TypeDefn(l) { this->readableName = "struct definition"; } ~StructDefn() { } virtual std::string getKind() override { return "struct"; } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) override; virtual TCResult generateDeclaration(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) override; std::vector bases; std::vector> fields; std::vector methods; }; struct ClassDefn : TypeDefn { ClassDefn(const Location& l) : TypeDefn(l) { this->readableName = "class definition"; } ~ClassDefn() { } virtual std::string getKind() override { return "class"; } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) override; virtual TCResult generateDeclaration(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) override; std::vector bases; std::vector initialisers; InitFunctionDefn* deinitialiser = 0; InitFunctionDefn* copyInitialiser = 0; InitFunctionDefn* moveInitialiser = 0; std::vector fields; std::vector methods; std::vector staticFields; std::vector staticMethods; std::vector nestedTypes; }; struct EnumDefn : TypeDefn { EnumDefn(const Location& l) : TypeDefn(l) { this->readableName = "enum definition"; } ~EnumDefn() { } virtual std::string getKind() override { return "enum"; } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) override; virtual TCResult generateDeclaration(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) override; struct Case { Location loc; std::string name; Expr* value = 0; }; std::vector cases; pts::Type* memberType = 0; }; struct UnionDefn : TypeDefn { UnionDefn(const Location& l) : TypeDefn(l) { this->readableName = "union definition"; } ~UnionDefn() { } virtual std::string getKind() override { return "union"; } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) override; virtual TCResult generateDeclaration(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) override; util::hash_map> cases; std::vector> transparentFields; }; struct TraitDefn : TypeDefn { TraitDefn(const Location& l) : TypeDefn(l) { this->readableName = "trait definition"; } ~TraitDefn() { } virtual std::string getKind() override { return "trait"; } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) override; virtual TCResult generateDeclaration(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) override; std::vector bases; std::vector methods; }; struct TypeExpr : Expr { TypeExpr(const Location& l, pts::Type* t) : Expr(l), type(t) { this->readableName = ""; } ~TypeExpr() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; pts::Type* type = 0; }; // a bit of a strange thing, but basically it's a kind of cast. struct MutabilityTypeExpr : Expr { MutabilityTypeExpr(const Location& l, bool m) : Expr(l), mut(m) { this->readableName = ""; } ~MutabilityTypeExpr() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; bool mut; }; struct Ident : Expr { Ident(const Location& l, const std::string& n) : Expr(l), name(n) { this->readableName = "identifier"; } ~Ident() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; std::string name; bool traverseUpwards = true; // for these cases: Foo(...) and Foo.staticAccess // where Foo is, respectively, a generic function and a generic type. PolyArgMapping_t mappings; }; struct RangeExpr : Expr { RangeExpr(const Location& loc) : Expr(loc) { this->readableName = "range expression"; } ~RangeExpr() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; Expr* start = 0; Expr* end = 0; Expr* step = 0; bool halfOpen = false; }; struct AllocOp : Expr { AllocOp(const Location& l) : Expr(l) { this->readableName = "alloc statement"; } ~AllocOp() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; pts::Type* allocTy = 0; std::vector counts; std::vector> args; Block* initBody = 0; bool isMutable = false; }; struct DeallocOp : Stmt { DeallocOp(const Location& l) : Stmt(l) { this->readableName = "free statement"; } ~DeallocOp() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; Expr* expr = 0; }; struct SizeofOp : Expr { SizeofOp(const Location& l) : Expr(l) { this->readableName = "sizeof expression"; } ~SizeofOp() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; Expr* expr = 0; }; struct TypeidOp : Expr { TypeidOp(const Location& l) : Expr(l) { this->readableName = "typeid expression"; } ~TypeidOp() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; Expr* expr = 0; }; struct ComparisonOp : Expr { ComparisonOp(const Location& loc) : Expr(loc) { this->readableName = "comparsion expression"; } ~ComparisonOp() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; std::vector exprs; std::vector> ops; }; struct BinaryOp : Expr { BinaryOp(const Location& loc, const std::string& o, Expr* l, Expr* r) : Expr(loc), op(o), left(l), right(r) { this->readableName = "binary expression"; } ~BinaryOp() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; std::string op; Expr* left = 0; Expr* right = 0; }; struct UnaryOp : Expr { UnaryOp(const Location& l) : Expr(l) { this->readableName = "unary expression"; } ~UnaryOp() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; std::string op; Expr* expr = 0; bool isPostfix = false; }; struct AssignOp : Expr { AssignOp(const Location& l) : Expr(l) { this->readableName = "assignment statement"; } ~AssignOp() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; std::string op; Expr* left = 0; Expr* right = 0; }; struct SubscriptOp : Expr { SubscriptOp(const Location& l) : Expr(l) { } ~SubscriptOp() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; Expr* expr = 0; Expr* inside = 0; }; struct SliceOp : Expr { SliceOp(const Location& l) : Expr(l) { this->readableName = "slice expression"; } ~SliceOp() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; Expr* expr = 0; Expr* start = 0; Expr* end = 0; }; struct SplatOp : Expr { SplatOp(const Location& l) : Expr(l) { this->readableName = "splat expression"; } ~SplatOp() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; Expr* expr = 0; }; struct SubscriptDollarOp : Expr { SubscriptDollarOp(const Location& l) : Expr(l) { this->readableName = "dollar expression"; } ~SubscriptDollarOp() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; }; struct FunctionCall : Expr { FunctionCall(const Location& l, const std::string& n) : Expr(l), name(n) { this->readableName = "function call"; } ~FunctionCall() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; sst::Expr* typecheckWithArguments(sst::TypecheckState* fs, const std::vector& args, fir::Type* inferred); std::string name; std::vector> args; PolyArgMapping_t mappings; bool traverseUpwards = true; }; struct ExprCall : Expr { ExprCall(const Location& l) : Expr(l) { this->readableName = "function call"; } ~ExprCall() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; sst::Expr* typecheckWithArguments(sst::TypecheckState* fs, const std::vector& args, fir::Type* inferred); Expr* callee = 0; std::vector> args; }; struct DotOperator : Expr { DotOperator(const Location& loc, Expr* l, Expr* r) : Expr(loc), left(l), right(r) { this->readableName = "dot operator"; } ~DotOperator() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; Expr* left = 0; Expr* right = 0; bool isStatic = false; }; struct LitNumber : Expr { LitNumber(const Location& l, const std::string& n) : Expr(l), num(n) { this->readableName = "number literal"; } ~LitNumber() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; std::string num; }; struct LitChar : Expr { LitChar(const Location& l, uint32_t val) : Expr(l), value(val) { this->readableName = "character literal"; } ~LitChar() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; uint32_t value = false; }; struct LitBool : Expr { LitBool(const Location& l, bool val) : Expr(l), value(val) { this->readableName = "boolean literal"; } ~LitBool() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; bool value = false; }; struct LitString : Expr { LitString(const Location& l, const std::string& s, bool isc) : Expr(l), str(s), isCString(isc) { this->readableName = "string literal"; } ~LitString() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; std::string str; bool isCString = false; }; struct LitNull : Expr { LitNull(const Location& l) : Expr(l) { this->readableName = "null literal"; } ~LitNull() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; }; struct LitTuple : Expr { LitTuple(const Location& l, const std::vector& its) : Expr(l), values(its) { this->readableName = "tuple literal"; } ~LitTuple() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; std::vector values; }; struct LitArray : Expr { LitArray(const Location& l, const std::vector& its) : Expr(l), values(its) { this->readableName = "array literal"; } ~LitArray() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; bool raw = false; pts::Type* explicitType = 0; std::vector values; }; struct RunDirective : Expr { RunDirective(const Location& l) : Expr(l) { this->readableName = "#run directive"; } ~RunDirective() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; // note: these two are mutually exclusive! Block* block = 0; Expr* insideExpr = 0; }; struct IfDirective : Stmt { IfDirective(const Location& l) : Stmt(l) { this->readableName = "#if directive"; } ~IfDirective() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; std::vector cases; Block* elseCase = 0; }; struct TopLevelBlock : Stmt { TopLevelBlock(const Location& l, const std::string& n) : Stmt(l), name(n) { this->readableName = "namespace"; } ~TopLevelBlock() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; std::string name; std::vector statements; VisibilityLevel visibility = VisibilityLevel::Internal; }; } ================================================ FILE: source/include/backend.h ================================================ // backend.h // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include "defs.h" namespace fir { struct Module; struct Function; } namespace backend { struct CompiledData { fir::Module* module = 0; }; namespace BackendCaps { enum Capabilities : int { EmitProgram = 0x01, EmitObject = 0x02, EmitAssembly = 0x04, JIT = 0x08, }; } enum class OptimisationLevel { Invalid, Debug, // -Ox None, // -O0 Minimal, // -O1 Normal, // -O2 Aggressive // -O3 }; enum class ProgOutputMode { Invalid, RunJit, // -run or -jit ObjectFile, // -c LLVMBitcode, // -emit-llvm Program // (default) }; enum class BackendOption { Invalid, None, LLVM, Interpreter, Assembly_x64, }; std::string capabilitiesToString(BackendCaps::Capabilities caps); struct Backend { BackendCaps::Capabilities getCapabilities() { return static_cast(this->capabilities); } bool hasCapability(BackendCaps::Capabilities cap) { return this->capabilities & cap; } static Backend* getBackendFromOption(BackendOption opt, CompiledData& cd, const std::vector& in, const std::string& out); virtual ~Backend() { } // in order of calling. virtual void performCompilation() = 0; virtual void optimiseProgram() = 0; virtual void writeOutput() = 0; virtual std::string str() = 0; protected: Backend(int caps, CompiledData& dat, const std::vector& inputs, const std::string& output) : capabilities(caps), compiledData(dat), inputFilenames(inputs), outputFilename(output) { } int capabilities; CompiledData& compiledData; std::vector inputFilenames; std::string outputFilename; }; struct x64Backend : Backend { x64Backend(CompiledData& dat, const std::vector& inputs, const std::string& output); virtual ~x64Backend() { } virtual void performCompilation() override; virtual void optimiseProgram() override; virtual void writeOutput() override; virtual std::string str() override; }; } ================================================ FILE: source/include/backends/interp.h ================================================ // interp.h // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include "backend.h" namespace fir::interp { struct InterpState; } namespace backend { struct FIRInterpBackend : Backend { FIRInterpBackend(CompiledData& dat, const std::vector& inputs, const std::string& output); virtual ~FIRInterpBackend(); virtual void performCompilation() override; virtual void optimiseProgram() override; virtual void writeOutput() override; virtual std::string str() override; protected: fir::interp::InterpState* is = 0; }; } ================================================ FILE: source/include/backends/llvm.h ================================================ // llvm.h // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #ifndef __STDC_CONSTANT_MACROS #define __STDC_CONSTANT_MACROS #endif #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS #endif #ifdef _MSC_VER #pragma warning(push, 0) #else #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" #endif #include "llvm/IR/Mangler.h" #include "llvm/IR/DataLayout.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/DynamicLibrary.h" #include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/RTDyldMemoryManager.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/ExecutionEngine/Orc/CompileUtils.h" #include "llvm/ExecutionEngine/Orc/LambdaResolver.h" #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" #include "llvm/ExecutionEngine/Orc/IRTransformLayer.h" #include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h" #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" #ifdef _MSC_VER #pragma warning(pop) #else #pragma GCC diagnostic pop #endif #include "backend.h" namespace llvm { class Module; class TargetMachine; class ExecutionEngine; class LLVMContext; class Function; } namespace backend { using EntryPoint_t = int (*)(int, const char**); struct LLVMJit { using OptimiseFunction = std::function(std::unique_ptr)>; void addModule(std::unique_ptr mod); llvm::JITEvaluatedSymbol findSymbol(const std::string& name); llvm::JITTargetAddress getSymbolAddress(const std::string& name); static LLVMJit* create(); private: LLVMJit(llvm::orc::JITTargetMachineBuilder JTMB, llvm::DataLayout DL); static llvm::Expected optimiseModule(llvm::orc::ThreadSafeModule TSM, const llvm::orc::MaterializationResponsibility& R); llvm::orc::ExecutionSession ES; llvm::orc::RTDyldObjectLinkingLayer ObjectLayer; llvm::orc::IRCompileLayer CompileLayer; llvm::orc::IRTransformLayer OptimiseLayer; llvm::DataLayout DL; llvm::orc::MangleAndInterner Mangle; llvm::orc::ThreadSafeContext Ctx; llvm::orc::JITDylib& dylib; }; struct LLVMBackend : Backend { LLVMBackend(CompiledData& dat, const std::vector& inputs, const std::string& output); virtual ~LLVMBackend() { } virtual void performCompilation() override; virtual void optimiseProgram() override; virtual void writeOutput() override; virtual std::string str() override; static llvm::LLVMContext& getLLVMContext(); static llvm::Module* translateFIRtoLLVM(fir::Module* mod); private: void setupTargetMachine(); EntryPoint_t getEntryFunctionFromJIT(); llvm::Function* entryFunction = 0; llvm::TargetMachine* targetMachine = 0; std::unique_ptr linkedModule; LLVMJit* jitInstance = 0; }; } ================================================ FILE: source/include/codegen.h ================================================ // codegen.h // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include "defs.h" #include "stcommon.h" #include "ir/irbuilder.h" namespace fir { struct Module; struct IRBuilder; namespace interp { struct InterpState; } } namespace sst { struct Expr; struct Stmt; struct Defn; struct Block; struct TypeDefn; struct BinaryOp; struct StateTree; struct FunctionDecl; struct FunctionDefn; struct FunctionCall; struct DefinitionTree; } namespace cgn { struct ControlFlowPoint { ControlFlowPoint(sst::Block* b, fir::IRBlock* bp, fir::IRBlock* cp) : block(b), breakPoint(bp), continuePoint(cp) { } sst::Block* block = 0; fir::IRBlock* breakPoint = 0; fir::IRBlock* continuePoint = 0; }; struct BlockPoint { BlockPoint(sst::Block* b) : block(b) { } sst::Block* block = 0; std::vector refCountedValues; std::vector raiiValues; }; struct CodegenState { enum class OperatorFn { None, Builtin, UserDefined }; CodegenState(const fir::IRBuilder& i); size_t id = 0; fir::Module* module = 0; fir::IRBuilder irb; std::pair entryFunction = { }; std::vector locationStack; util::hash_map valueMap; std::vector methodSelfStack; util::hash_map methodList; util::hash_map typeDefnMap; util::hash_map compilerSupportDefinitions; size_t _debugIRIndent = 0; void pushIRDebugIndentation(); void printIRDebugMessage(const std::string& msg, const std::vector& vals); void popIRDebugIndentation(); void pushLoc(const Location& l); void pushLoc(sst::Stmt* stmt); void popLoc(); Location loc(); void enterMethodBody(fir::Function* method, fir::Value* self); void leaveMethodBody(); bool isInMethodBody(); fir::Value* getMethodSelf(); std::vector functionStack; fir::Function* getCurrentFunction(); void enterFunction(fir::Function* fn); void leaveFunction(); std::vector breakingPointStack; ControlFlowPoint getCurrentCFPoint(); void enterBreakableBody(const ControlFlowPoint& cfp); ControlFlowPoint leaveBreakableBody(); std::vector blockPointStack; BlockPoint getCurrentBlockPoint(); void enterBlock(const BlockPoint& bp); void leaveBlock(); std::vector subscriptArrayLengthStack; fir::Value* getCurrentSubscriptArrayLength(); void enterSubscriptWithLength(fir::Value* len); void leaveSubscript(); CGResult performBinaryOperation(const Location& loc, std::pair lhs, std::pair rhs, std::string op); CGResult performLogicalBinaryOperation(sst::BinaryOp* bo); std::pair autoCastValueTypes(fir::Value* lhs, fir::Value* rhs); fir::Value* oneWayAutocast(fir::Value* from, fir::Type* target); fir::Value* getDefaultValue(fir::Type* type); fir::Value* getConstructedStructValue(fir::StructType* str, const std::vector& args); fir::Value* constructClassWithArguments(fir::ClassType* cls, sst::FunctionDefn* constr, const std::vector& args); fir::Value* callVirtualMethod(sst::FunctionCall* call); fir::ConstantValue* unwrapConstantNumber(fir::ConstantValue* cv); fir::ConstantValue* unwrapConstantNumber(fir::ConstantNumber* cv, fir::Type* target); CGResult getStructFieldImplicitly(std::string name); fir::Function* getOrDeclareLibCFunction(std::string name); bool isInsideGlobalInitFunc = false; // this one holds the finalised global initialiser function -- this one is supposed to // call all the pieces; we always regenerate this function when we call finishGlobalInitFunction(). fir::Function* finalisedGlobalInitFunction = 0; // this is getting a bit complicated. this holds each "piece" of the global init function, // where each piece probably corresponds to the initialisation of a single global value. std::vector> globalInitPieces; bool isWithinGlobalInitFunction(); fir::IRBlock* enterGlobalInitFunction(fir::GlobalValue* val); void leaveGlobalInitFunction(fir::IRBlock* restore); void finishGlobalInitFunction(); void generateDecompositionBindings(const DecompMapping& bind, CGResult rhs, bool allowref); util::hash_map getNameIndexMap(sst::FunctionDefn* fd); std::vector codegenAndArrangeFunctionCallArguments(sst::Defn* target, fir::FunctionType* ft, const std::vector& args); void addVariableUsingStorage(sst::VarDefn* var, fir::Value* ptr); void createWhileLoop(const std::function& check, const std::function& body); std::pair getOperatorFunctionForTypes(fir::Type* a, fir::Type* b, std::string op); bool isRefCountedType(fir::Type* type); void incrementRefCount(fir::Value* val); void decrementRefCount(fir::Value* val); void addRefCountedValue(fir::Value* val); void removeRefCountedValue(fir::Value* val); std::vector getRefCountedValues(); void autoAssignRefCountedValue(fir::Value* lhs, fir::Value* rhs, bool isInitial); void addRAIIOrRCValueIfNecessary(fir::Value* val, fir::Type* typeOverride = 0); void addRAIIValue(fir::Value* val); void removeRAIIValue(fir::Value* val); std::vector getRAIIValues(); sst::FunctionDefn* findMatchingMethodInType(sst::TypeDefn* td, sst::FunctionDecl* fn); bool isRAIIType(fir::Type* ty); bool typeHasDestructor(fir::Type* ty); bool typeHasCopyConstructor(fir::Type* ty); bool typeHasMoveConstructor(fir::Type* ty); void callDestructor(fir::Value* val); fir::Value* copyRAIIValue(fir::Value* value); void copyRAIIValue(fir::Value* from, fir::Value* target, bool enableMoving = true); void moveRAIIValue(fir::Value* from, fir::Value* target); }; fir::Module* codegen(sst::DefinitionTree* dtree); } ================================================ FILE: source/include/container.h ================================================ // container.h // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include #include #include #include #include #include #include "allocator.h" namespace util { // only allows for insertions. // hopefully faster than FastVector. template struct FastInsertVector { FastInsertVector() { this->length = 0; } FastInsertVector(const FastInsertVector& other) { for(auto c : other.chunks) { auto nc = static_cast(mem::allocate_memory(sizeof(ValueType) * ChunkSize)); memmove(nc, c, sizeof(ValueType) * ChunkSize); this->chunks.push_back(nc); } this->length = other.length; } FastInsertVector& operator = (const FastInsertVector& other) { auto copy = other; std::swap(copy, *this); return *this; } FastInsertVector(FastInsertVector&& other) noexcept { // move. this->chunks = std::move(other.chunks); this->length = other.length; other.length = 0; } FastInsertVector& operator = (FastInsertVector&& other) noexcept { if(this != &other) { for(auto p : this->chunks) mem::deallocate_memory(p, sizeof(ValueType) * ChunkSize); // move. this->chunks = std::move(other.chunks); this->length = other.length; other.length = 0; } return *this; } ~FastInsertVector() { this->clear(); } ValueType& operator [] (size_t index) const { size_t cind = index / ChunkSize; size_t offs = index % ChunkSize; assert(cind < this->chunks.size()); return *(static_cast(this->chunks[cind] + offs)); } ValueType* getNextSlotAndIncrement() { size_t addr = this->length; if(addr >= (ChunkSize * this->chunks.size())) makeNewChunk(); this->length++; auto ret = (chunks.back() + (addr % ChunkSize)); return ret; } size_t size() const { return this->length; } void clear() { size_t i = 0; for(auto c : this->chunks) { for(size_t k = 0; k < ChunkSize && i < this->length; k++, i++) (c + k)->~ValueType(); mem::deallocate_memory(c, sizeof(ValueType) * ChunkSize); } this->length = 0; this->chunks.clear(); } private: void makeNewChunk() { this->chunks.push_back(static_cast(mem::allocate_memory(sizeof(ValueType) * ChunkSize))); } // possibly use a faster implementation?? since we're just storing pointers idk if there's a point. size_t length; std::vector chunks; }; struct MemoryPool_base { virtual void clear() = 0; virtual ~MemoryPool_base() { } }; template struct MemoryPool : MemoryPool_base { MemoryPool() { } ~MemoryPool() { this->storage.clear(); } MemoryPool(const MemoryPool& other) { this->storage = other.storage; } MemoryPool& operator = (const MemoryPool& other) { auto copy = other; std::swap(copy, *this); return *this; } MemoryPool(MemoryPool&& other) noexcept { this->storage = std::move(other.storage); } MemoryPool& operator = (MemoryPool&& other) noexcept { if(this != &other) this->storage = std::move(other.storage); return *this; } template ValueType* operator () (Args&&... args) { return this->construct(std::forward(args)...); } template ValueType* construct(Args&&... args) { return new (this->storage.getNextSlotAndIncrement()) ValueType(std::forward(args)...); } virtual void clear() override { this->storage.clear(); } private: FastInsertVector storage; }; } ================================================ FILE: source/include/defs.h ================================================ // defs.h // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include #include #include #include #include #include "container.h" struct Identifier; enum class VisibilityLevel; namespace fir { struct Type; struct Name; } namespace pts { struct Type; } namespace zpr { template struct print_formatter) || (std::is_pointer_v && std::is_base_of_v>) >::type> { std::string print(const T& x, const format_args&) { return x->str(); } }; template <> struct print_formatter { std::string print(const Identifier& x, const format_args& args); }; template <> struct print_formatter { std::string print(const VisibilityLevel& x, const format_args& args); }; } [[noreturn]] void doTheExit(bool trace = true); template [[noreturn]] inline void _error_and_exit(const char* fmt, Ts&&... ts) { // tinyformat::format(std::cerr, fmt, ts...); fprintf(stderr, "%s\n", zpr::sprint(fmt, ts...).c_str()); doTheExit(); } namespace platform { void printStackTrace(); } template [[noreturn]] inline void compiler_crash(const char* fmt, Ts&&... ts) { fprintf(stderr, "%s\n", zpr::sprint(fmt, ts...).c_str()); platform::printStackTrace(); abort(); } template std::string strprintf(const char* fmt, Ts&&... ts) { // return tinyformat::format(fmt, ts...); return zpr::sprint(fmt, ts...); } #define __nothing #ifdef NDEBUG #define iceAssert(x) ((void) (x)) #else #define iceAssert(x) ((x) ? ((void) (0)) : _error_and_exit("compiler assertion at %s:%d, cause:\n'%s' evaluated to false\n", __FILE__, __LINE__, #x)) #endif #define TAB_WIDTH 4 #define dcast(t, v) (dynamic_cast(v)) namespace util { template using hash_map = std::unordered_map; } namespace fir { struct Type; struct Value; } namespace sst { struct Expr; struct Stmt; struct Defn; } enum class IdKind { Invalid, Name, Function, Type, }; #define COLOUR_RESET "\033[0m" #define COLOUR_BLACK "\033[30m" // Black #define COLOUR_RED "\033[31m" // Red #define COLOUR_GREEN "\033[32m" // Green #define COLOUR_YELLOW "\033[33m" // Yellow #define COLOUR_BLUE "\033[34m" // Blue #define COLOUR_MAGENTA "\033[35m" // Magenta #define COLOUR_CYAN "\033[36m" // Cyan #define COLOUR_WHITE "\033[37m" // White #define COLOUR_BLACK_BOLD "\033[1m" // Bold Black #define COLOUR_RED_BOLD "\033[1m\033[31m" // Bold Red #define COLOUR_GREEN_BOLD "\033[1m\033[32m" // Bold Green #define COLOUR_YELLOW_BOLD "\033[1m\033[33m" // Bold Yellow #define COLOUR_BLUE_BOLD "\033[1m\033[34m" // Bold Blue #define COLOUR_MAGENTA_BOLD "\033[1m\033[35m" // Bold Magenta #define COLOUR_CYAN_BOLD "\033[1m\033[36m" // Bold Cyan #define COLOUR_WHITE_BOLD "\033[1m\033[37m" // Bold White #define COLOUR_GREY_BOLD "\033[30;1m" // Bold Grey template std::string strbold(const char* fmt, Ts&&... ts) { return std::string(COLOUR_RESET) + std::string(COLOUR_BLACK_BOLD) + strprintf(fmt, ts...) + std::string(COLOUR_RESET); } namespace sst { struct StateTree; struct Scope { Scope() { } Scope(StateTree* st); StateTree* stree = 0; const Scope* prev = 0; mutable std::vector cachedComponents; std::string string() const; const std::vector& components() const; const Scope& appending(const std::string& name) const; }; } struct Identifier { Identifier() : name(""), kind(IdKind::Invalid) { } Identifier(const std::string& n, IdKind k) : name(n), kind(k) { } std::string name; sst::Scope scope; std::vector params; fir::Type* returnType = nullptr; IdKind kind; std::string str() const; std::string mangled___() const; fir::Name convertToName() const; bool operator == (const Identifier& other) const; bool operator != (const Identifier& other) const; }; struct Location { size_t fileID = 0; size_t line = 0; size_t col = 0; size_t len = 0; bool operator == (const Location& other) const { return this->col == other.col && this->line == other.line && this->len == other.len && this->fileID == other.fileID; } bool operator != (const Location& other) const { return !(*this == other); } Location unionWith(const Location& x) const { return unionOf(*this, x); } static Location unionOf(const Location& a, const Location& b) { if(a.fileID != b.fileID || a.line != b.line) return a; Location ret; ret.fileID = a.fileID; ret.line = a.line; auto end = std::max(a.col + a.len, b.col + b.len); if(a.col <= b.col) { ret.col = a.col; } else if(b.col < a.col) { ret.col = b.col; } ret.len = (end - ret.col); return ret; } std::string toString() const; std::string shortString() const; }; struct Locatable { Locatable(const Location& l, const std::string& readable) : loc(l), readableName(readable) { } virtual ~Locatable() { } Location loc; std::string readableName; }; struct BareError; struct SpanError; struct SimpleError; struct OverloadError; struct ExampleMsg; //? in order of complexity, i guess? enum class ErrKind { Bare, // error without context Simple, // error with context Span, // error with context, but with squiggles within those (general case of Overload, // most complex one; built specifically to handle multiple candidates and such Example, // same as a SimpleError, but we give the "context" as a string. }; enum class MsgType { Note, Warning, Error }; namespace util { struct ESpan { ESpan() { } ESpan(const Location& l, const std::string& m) : loc(l), msg(m) { } Location loc; std::string msg; std::string colour; }; BareError* make_BareError(const std::string& m, MsgType t = MsgType::Error); SpanError* make_SpanError(SimpleError* se, const std::vector& s = { }, MsgType t = MsgType::Error); SimpleError* make_SimpleError(const Location& l, const std::string& m, MsgType t = MsgType::Error); OverloadError* make_OverloadError(SimpleError* se, MsgType t = MsgType::Error); ExampleMsg* make_ExampleMsg(const std::string& eg, MsgType t = MsgType::Note); } struct ErrorMsg { virtual ~ErrorMsg() { } virtual void post() = 0; virtual ErrorMsg* append(ErrorMsg* e) { this->subs.push_back(e); return this; } virtual ErrorMsg* prepend(ErrorMsg* e) { this->subs.insert(this->subs.begin(), e); return this; } [[noreturn]] void postAndQuit() { this->post(); doTheExit(); } ErrKind kind; MsgType type; std::vector subs; protected: ErrorMsg(ErrKind k, MsgType t) : kind(k), type(t) { } template friend struct util::MemoryPool; template friend struct util::FastInsertVector; }; struct BareError : ErrorMsg { template static BareError* make(const char* fmt, Ts&&... ts) { return util::make_BareError(strprintf(fmt, ts...)); } template static BareError* make(MsgType t, const char* fmt, Ts&&... ts) { return util::make_BareError(strprintf(fmt, ts...), t); } virtual void post() override; virtual BareError* append(ErrorMsg* e) override { this->subs.push_back(e); return this; } virtual BareError* prepend(ErrorMsg* e) override { this->subs.insert(this->subs.begin(), e); return this; } std::string msg; protected: BareError() : ErrorMsg(ErrKind::Bare, MsgType::Error) { } BareError(const std::string& m, MsgType t) : ErrorMsg(ErrKind::Bare, t), msg(m) { } template friend struct util::MemoryPool; template friend struct util::FastInsertVector; }; struct SimpleError : ErrorMsg { template static SimpleError* make(const Location& l, const char* fmt, Ts&&... ts) { return util::make_SimpleError(l, strprintf(fmt, ts...)); } template static SimpleError* make(MsgType t, const Location& l, const char* fmt, Ts&&... ts) { return util::make_SimpleError(l, strprintf(fmt, ts...), t); } virtual void post() override; virtual SimpleError* append(ErrorMsg* e) override { this->subs.push_back(e); return this; } virtual SimpleError* prepend(ErrorMsg* e) override { this->subs.insert(this->subs.begin(), e); return this; } Location loc; std::string msg; // just a hacky thing to print some words (eg. '(call site)') before the context. bool printContext = true; std::string wordsBeforeContext; protected: SimpleError() : ErrorMsg(ErrKind::Simple, MsgType::Error) { } SimpleError(const Location& l, const std::string& m, MsgType t) : ErrorMsg(ErrKind::Bare, t), loc(l), msg(m) { } template friend struct util::MemoryPool; template friend struct util::FastInsertVector; }; struct ExampleMsg : ErrorMsg { static ExampleMsg* make(const std::string& eg) { return util::make_ExampleMsg(eg); } virtual void post() override; virtual ExampleMsg* append(ErrorMsg* e) override { this->subs.push_back(e); return this; } virtual ExampleMsg* prepend(ErrorMsg* e) override { this->subs.insert(this->subs.begin(), e); return this; } std::string example; protected: ExampleMsg() : ErrorMsg(ErrKind::Example, MsgType::Note) { } ExampleMsg(const std::string& eg, MsgType t) : ErrorMsg(ErrKind::Example, t), example(eg) { } template friend struct util::MemoryPool; template friend struct util::FastInsertVector; }; struct SpanError : ErrorMsg { SpanError* add(const util::ESpan& s); static SpanError* make(SimpleError* se = 0, const std::vector& s = { }) { return util::make_SpanError(se, s, MsgType::Error); } static SpanError* make(MsgType t, SimpleError* se = 0, const std::vector& s = { }) { return util::make_SpanError(se, s, t); } virtual void post() override; virtual SpanError* append(ErrorMsg* e) override { this->subs.push_back(e); return this; } virtual SpanError* prepend(ErrorMsg* e) override { this->subs.insert(this->subs.begin(), e); return this; } SimpleError* top = 0; std::vector spans; // again, another internal flag; this one controls whether or not to underline the original location. bool highlightActual = true; protected: SpanError() : SpanError(0, { }, MsgType::Error) { } SpanError(SimpleError* se, const std::vector& s, MsgType t) : ErrorMsg(ErrKind::Span, t), top(se), spans(s) { } template friend struct util::MemoryPool; template friend struct util::FastInsertVector; }; struct OverloadError : ErrorMsg { void clear(); static OverloadError* make(SimpleError* se = 0) { return util::make_OverloadError(se, MsgType::Error); } static OverloadError* make(MsgType t, SimpleError* se = 0) { return util::make_OverloadError(se, t); } virtual void post() override; virtual OverloadError* append(ErrorMsg* e) override { this->subs.push_back(e); return this; } virtual OverloadError* prepend(ErrorMsg* e) override { this->subs.insert(this->subs.begin(), e); return this; } OverloadError& addCand(Locatable* d, ErrorMsg* e); SimpleError* top = 0; util::hash_map cands; protected: OverloadError() : ErrorMsg(ErrKind::Overload, MsgType::Error) { } OverloadError(SimpleError* se, MsgType t) : ErrorMsg(ErrKind::Overload, t), top(se) { } template friend struct util::MemoryPool; template friend struct util::FastInsertVector; }; struct ErrorException : public std::exception { ErrorException(ErrorMsg* msg) : err(msg) { } ErrorMsg* err; }; struct TCResult { enum class RK { Invalid, Statement, Expression, Definition, Parametric, Dummy, Error }; union { sst::Stmt* _st; sst::Expr* _ex; sst::Defn* _df; ErrorMsg* _pe; }; RK _kind = RK::Invalid; ~TCResult() { } TCResult(RK k) : _kind(k) { _st = 0; } explicit TCResult(sst::Stmt* s) : _kind(RK::Statement) { _st = s; } explicit TCResult(sst::Expr* e) : _kind(RK::Expression) { _ex = e; } explicit TCResult(sst::Defn* d) : _kind(RK::Definition) { _df = d; } explicit TCResult(ErrorMsg* pe) : _kind(RK::Error) { _pe = pe; } TCResult(const TCResult& r) { this->_kind = r._kind; if(this->isError()) this->_pe = r._pe; else if(this->isStmt()) this->_st = r._st; else if(this->isExpr()) this->_ex = r._ex; else if(this->isDefn()) this->_df = r._df; } TCResult(TCResult&& r) noexcept { this->_kind = r._kind; if(this->isError()) { this->_pe = r._pe; r._pe = 0; } else if(this->isStmt()) { this->_st = r._st; r._st = 0; } else if(this->isExpr()) { this->_ex = r._ex; r._ex = 0; } else if(this->isDefn()) { this->_df = r._df; r._df = 0; } } TCResult& operator = (const TCResult& r) { TCResult tmp(r); *this = std::move(tmp); return *this; } TCResult& operator = (TCResult&& r) noexcept { if(&r != this) { this->_kind = r._kind; if(this->isError()) { this->_pe = r._pe; r._pe = 0; } else if(this->isStmt()) { this->_st = r._st; r._st = 0; } else if(this->isExpr()) { this->_ex = r._ex; r._ex = 0; } else if(this->isDefn()) { this->_df = r._df; r._df = 0; } } return *this; } ErrorMsg* error() const { if(this->_kind != RK::Error || !this->_pe) { _error_and_exit("not error\n"); } return this->_pe; } sst::Expr* expr() const; sst::Defn* defn() const; //* stmt() is the most general case -- definitions and expressions are both statements. // note: we need the definition of sst::Stmt and sst::Expr to do safe dynamic casting, so it's in identifier.cpp. sst::Stmt* stmt() const; bool isError() const { return this->_kind == RK::Error; } bool isStmt() const { return this->_kind == RK::Statement; } bool isExpr() const { return this->_kind == RK::Expression; } bool isDefn() const { return this->_kind == RK::Definition; } bool isParametric() const { return this->_kind == RK::Parametric; } bool isDummy() const { return this->_kind == RK::Dummy; } static TCResult getParametric() { return TCResult(RK::Parametric); } static TCResult getDummy() { return TCResult(RK::Dummy); } }; struct CGResult { enum class VK { Invalid, Normal, EarlyOut, }; CGResult() : CGResult(0) { } explicit CGResult(fir::Value* v) noexcept : value(v), kind(VK::Normal) { } explicit CGResult(fir::Value* v, VK k) noexcept : value(v), kind(k) { } fir::Value* operator -> () { return this->value; } fir::Value* value = 0; VK kind = VK::Invalid; }; namespace std { template<> struct hash { std::size_t operator()(const Identifier& k) const { using std::size_t; using std::hash; using std::string; // Compute individual hash values for first, // second and third and combine them using XOR // and bit shifting: // return ((hash()(k.name) ^ (hash>()(k.scope) << 1)) >> 1) ^ (hash()(k.third) << 1); return hash()(k.str()); } }; } enum class VisibilityLevel { Invalid, Public, Private, Internal, }; struct TypeConstraints_t { std::vector protocols; int pointerDegree = 0; bool operator == (const TypeConstraints_t& other) const { return this->protocols == other.protocols && this->pointerDegree == other.pointerDegree; } }; using TypeParamMap_t = util::hash_map; struct PolyArgMapping_t { struct SingleArg { size_t index; std::string name; pts::Type* type; }; std::vector maps; bool empty() const { return maps.empty(); } void add(const std::string& name, pts::Type* t); void add(size_t idx, pts::Type* t); std::string print() const; static inline PolyArgMapping_t none() { return PolyArgMapping_t(); } }; namespace util { std::string typeParamMapToString(const std::string& name, const TypeParamMap_t& map); template std::string listToEnglish(const std::vector& list, bool quote = true) { auto printitem = [quote](const T& i) -> std::string { return strprintf("%s%s%s", quote ? "'" : "", i, quote ? "'" : ""); }; std::string mstr; if(list.size() == 1) { mstr = printitem(list[0]); } else if(list.size() == 2) { mstr = strprintf("%s and %s", printitem(list[0]), printitem(list[1])); } else { for(size_t i = 0; i < list.size() - 1; i++) mstr += strprintf("%s, ", printitem(list[i])); // oxford comma is important. mstr += strprintf("and %s", printitem(list.back())); } return mstr; } } namespace Operator { extern const std::string Plus; extern const std::string Minus; extern const std::string Multiply; extern const std::string Divide; extern const std::string Modulo; extern const std::string UnaryPlus; extern const std::string UnaryMinus; extern const std::string PointerDeref; extern const std::string AddressOf; extern const std::string BitwiseNot; extern const std::string BitwiseAnd; extern const std::string BitwiseOr; extern const std::string BitwiseXor; extern const std::string BitwiseShiftLeft; extern const std::string BitwiseShiftRight; extern const std::string LogicalNot; extern const std::string LogicalAnd; extern const std::string LogicalOr; extern const std::string CompareEQ; extern const std::string CompareNEQ; extern const std::string CompareLT; extern const std::string CompareLEQ; extern const std::string CompareGT; extern const std::string CompareGEQ; extern const std::string Assign; extern const std::string PlusEquals; extern const std::string MinusEquals; extern const std::string MultiplyEquals; extern const std::string DivideEquals; extern const std::string ModuloEquals; extern const std::string BitwiseShiftLeftEquals; extern const std::string BitwiseShiftRightEquals; extern const std::string BitwiseXorEquals; extern const std::string BitwiseAndEquals; extern const std::string BitwiseOrEquals; extern const std::string TypeCast; extern const std::string TypeIs; std::string getNonAssignmentVersion(const std::string& op); bool isArithmetic(const std::string& op); bool isComparison(const std::string& op); bool isAssignment(const std::string& op); bool isBitwise(const std::string& op); } // https://stackoverflow.com/questions/28367913/how-to-stdhash-an-unordered-stdpair template void _hash_combine(std::size_t& seed, const T& key) { std::hash hasher; seed ^= hasher(key) + 0x9e3779b9 + (seed << 6) + (seed >> 2); } namespace std { template struct hash> { size_t operator () (const std::pair& p) const { size_t seed = 0; _hash_combine(seed, p.first); _hash_combine(seed, p.second); return seed; } }; } // defer implementation // credit: gingerBill // shamelessly stolen from https://github.com/gingerBill/gb namespace __dontlook { // NOTE(bill): Stupid fucking templates template struct gbRemoveReference { typedef T Type; }; template struct gbRemoveReference { typedef T Type; }; template struct gbRemoveReference { typedef T Type; }; /// NOTE(bill): "Move" semantics - invented because the C++ committee are idiots (as a collective not as indiviuals (well a least some aren't)) template inline T &&gb_forward(typename gbRemoveReference::Type &t) { return static_cast(t); } template inline T &&gb_forward(typename gbRemoveReference::Type &&t) { return static_cast(t); } template inline T &&gb_move (T &&t) { return static_cast::Type &&>(t); } template struct gbprivDefer { F f; gbprivDefer(F &&f) : f(gb_forward(f)) {} ~gbprivDefer() { f(); } }; template gbprivDefer gb__defer_func(F &&f) { return gbprivDefer(gb_forward(f)); } } #define GB_DEFER_1(x, y) x##y #define GB_DEFER_2(x, y) GB_DEFER_1(x, y) #define GB_DEFER_3(x) GB_DEFER_2(x, __COUNTER__) #define defer(code) auto GB_DEFER_3(_defer_) = __dontlook::gb__defer_func([&]()->void{code;}) ================================================ FILE: source/include/errors.h ================================================ // errors.h // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include "defs.h" #include "precompile.h" template inline void debuglog(const char* s, Ts&&... ts) { // auto out = tinyformat::format(s, ts...); auto out = strprintf(s, ts...); fprintf(stderr, "%s", out.c_str()); } template inline void debuglogln(const char* s, Ts&&... ts) { auto out = strprintf(s, ts...); fprintf(stderr, "%s\n", out.c_str()); } #define INTUNSPEC_TYPE_STRING "int" #define UINTUNSPEC_TYPE_STRING "uint" #define FLOAT_TYPE_STRING "float" #define DOUBLE_TYPE_STRING "double" #define INT8_TYPE_STRING "i8" #define INT16_TYPE_STRING "i16" #define INT32_TYPE_STRING "i32" #define INT64_TYPE_STRING "i64" #define INT128_TYPE_STRING "i128" #define UINT8_TYPE_STRING "u8" #define UINT16_TYPE_STRING "u16" #define UINT32_TYPE_STRING "u32" #define UINT64_TYPE_STRING "u64" #define UINT128_TYPE_STRING "u128" #define FLOAT32_TYPE_STRING "f32" #define FLOAT64_TYPE_STRING "f64" #define FLOAT128_TYPE_STRING "f128" #define STRING_TYPE_STRING "string" #define CHARACTER_TYPE_STRING "char" #define CHARACTER_SLICE_TYPE_STRING "str" #define UNICODE_STRING_TYPE_STRING "ustring" #define UNICODE_CHARACTER_TYPE_STRING "rune" #define BOOL_TYPE_STRING "bool" #define VOID_TYPE_STRING "void" #define ANY_TYPE_STRING "any" namespace frontend { const std::string& getFilenameFromID(size_t fileID); std::string getFilenameFromPath(const std::string& path); } std::string __error_gen_internal(const Location& loc, const std::string& msg, const char* type, bool context, bool multiPart); template std::string __error_gen(const Location& loc, const char* msg, const char* type, bool, Ts&&... ts) { return __error_gen_internal(loc, strprintf(msg, ts...), type, true, false); } #define ERROR_FUNCTION(name, type, attr, doexit) \ template [[attr]] void name (const char* fmt, Ts&&... ts) \ { fputs(__error_gen(Location(), fmt, type, doexit, ts...).c_str(), stderr); if(doexit) doTheExit(false); } \ \ template [[attr]] void name (Locatable* e, const char* fmt, Ts&&... ts) \ { fputs(__error_gen(e ? e->loc : Location(), fmt, type, doexit, ts...).c_str(), stderr); if(doexit) doTheExit(false); } \ \ template [[attr]] void name (const Location& loc, const char* fmt, Ts&&... ts) \ { fputs(__error_gen(loc, fmt, type, doexit, ts...).c_str(), stderr); if(doexit) doTheExit(false); } ERROR_FUNCTION(error, "error", noreturn, true); ERROR_FUNCTION(info, "note", maybe_unused, false); ERROR_FUNCTION(warn, "warning", maybe_unused, false); ================================================ FILE: source/include/frontend.h ================================================ // frontend.h // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include "precompile.h" #include "lexer.h" #include "parser.h" #include "platform.h" #include #include namespace sst { struct DefinitionTree; } namespace fir { struct Module; } namespace backend { enum class BackendOption; enum class ProgOutputMode; enum class OptimisationLevel; } namespace frontend { std::string getParameter(const std::string& arg); std::string getVersion(); backend::ProgOutputMode getOutputMode(); backend::OptimisationLevel getOptLevel(); backend::BackendOption getBackendOption(); bool getPrintFIR(); bool getPrintLLVMIR(); bool getPrintProfileStats(); bool getAbortOnError(); bool getCanFFIEscape(); bool getIsFreestanding(); bool getIsNoStandardLibraries(); bool getIsPositionIndependent(); bool getIsNoRuntimeChecks(); bool getIsNoRuntimeErrorStrings(); bool getIsReplMode(); std::vector getFrameworksToLink(); std::vector getFrameworkSearchPaths(); std::vector getLibrariesToLink(); std::vector getLibrarySearchPaths(); struct DependencyGraph; struct CollectorState { std::unordered_set importedFiles; std::map parsed; util::hash_map dtrees; util::hash_map binaryOps; util::hash_map prefixOps; util::hash_map postfixOps; DependencyGraph* graph = 0; std::string fullMainFile; std::vector allFiles; size_t nativeWordSize = 0; // for statistics i guess size_t totalLinesOfCode = 0; }; // fir::Module* collectFiles(std::string filename); void collectFiles(const std::string& mainfile, CollectorState* state); void parseFiles(CollectorState* state); sst::DefinitionTree* typecheckFiles(CollectorState* state); fir::Module* generateFIRModule(CollectorState* state, sst::DefinitionTree* maintree); std::pair parseCmdLineOpts(int argc, char** argv); struct FileInnards { lexer::TokenList tokens; std::string_view fileContents; util::FastInsertVector lines; std::vector importIndices; bool didLex = false; }; FileInnards& getFileState(const std::string& name); FileInnards lexTokensFromString(const std::string& fakename, const std::string_view& str); std::string getPathFromFile(const std::string& path); std::string getFilenameFromPath(const std::string& path); std::string getFullPathOfFile(const std::string& partial); std::string removeExtensionFromFilename(const std::string& name); void cachePreExistingFilename(const std::string& name); std::string getFileContents(const std::string& fullPath); const std::string& getFilenameFromID(size_t fileID); size_t getFileIDFromFilename(const std::string& name); lexer::TokenList& getFileTokens(const std::string& fullPath); const util::FastInsertVector& getFileLines(size_t id); const std::vector& getImportTokenLocationsForFile(const std::string& filename); std::string resolveImport(const std::string& imp, const Location& loc, const std::string& fullPath); struct ImportThing { std::string name; std::vector importAs; bool pubImport = false; Location loc; }; // dependency system struct DepNode { std::string name; // mainly to aid error reporting std::vector> users; int index = -1; int lowlink = -1; bool onStack = false; }; struct Dep { DepNode* from = 0; DepNode* to = 0; ImportThing ithing; }; struct DependencyGraph { std::vector nodes; std::map> edgesFrom; std::stack stack; std::vector getDependenciesOf(const std::string& name); void addModuleDependency(const std::string& from, const std::string& to, const ImportThing& ithing); std::vector> findCyclicDependencies(); }; std::vector checkForCycles(const std::string& topmod, frontend::DependencyGraph* graph); frontend::DependencyGraph* buildDependencyGraph(frontend::DependencyGraph* graph, const std::string& full, util::hash_map& visited); } ================================================ FILE: source/include/gluecode.h ================================================ // gluecode.h // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include #include #include #include "stcommon.h" #include "string_consts.h" #define DEBUG_RUNTIME_GLUE_MASTER 0 #define DEBUG_STRING_MASTER (0 & DEBUG_RUNTIME_GLUE_MASTER) #define DEBUG_STRING_ALLOCATION (1 & DEBUG_STRING_MASTER) #define DEBUG_STRING_REFCOUNTING (1 & DEBUG_STRING_MASTER) #define DEBUG_ARRAY_MASTER (0 & DEBUG_RUNTIME_GLUE_MASTER) #define DEBUG_ARRAY_ALLOCATION (1 & DEBUG_ARRAY_MASTER) #define DEBUG_ARRAY_REFCOUNTING (1 & DEBUG_ARRAY_MASTER) #define DEBUG_ANY_MASTER (1 & DEBUG_RUNTIME_GLUE_MASTER) #define DEBUG_ANY_ALLOCATION (1 & DEBUG_ANY_MASTER) #define DEBUG_ANY_REFCOUNTING (1 & DEBUG_ANY_MASTER) #define BUILTIN_ANY_DATA_BYTECOUNT 32 #define BUILTIN_ANY_FLAG_MASK 0x8000000000000000 namespace fir { struct Value; struct Function; struct ClassType; struct UnionType; struct ArraySliceType; struct DynamicArrayType; } namespace sst { struct FunctionDefn; } namespace cgn { struct CodegenState; namespace glue { void printRuntimeError(CodegenState* cs, fir::Value* pos, const std::string& msg, const std::vector& args); namespace string { fir::Function* getCloneFunction(CodegenState* cs); fir::Function* getAppendFunction(CodegenState* cs); fir::Function* getCompareFunction(CodegenState* cs); fir::Function* getCharAppendFunction(CodegenState* cs); fir::Function* getUnicodeLengthFunction(CodegenState* cs); fir::Function* getConstructFromTwoFunction(CodegenState* cs); fir::Function* getConstructWithCharFunction(CodegenState* cs); fir::Function* getRefCountIncrementFunction(CodegenState* cs); fir::Function* getRefCountDecrementFunction(CodegenState* cs); fir::Function* getBoundsCheckFunction(CodegenState* cs, bool isDecomp); } namespace array { fir::Function* getCloneFunction(CodegenState* cs, fir::Type* arrtype); fir::Function* getAppendFunction(CodegenState* cs, fir::DynamicArrayType* arrtype); fir::Function* getPopElementFromBackFunction(CodegenState* cs, fir::Type* arrtype); fir::Function* getBoundsCheckFunction(CodegenState* cs, bool isPerformingDecomposition); fir::Function* getElementAppendFunction(CodegenState* cs, fir::DynamicArrayType* arrtype); fir::Function* getCompareFunction(CodegenState* cs, fir::Type* arrtype, fir::Function* opf); fir::Function* getConstructFromTwoFunction(CodegenState* cs, fir::DynamicArrayType* arrtype); fir::Function* getIncrementArrayRefCountFunction(CodegenState* cs, fir::Type* arrtype); fir::Function* getDecrementArrayRefCountFunction(CodegenState* cs, fir::Type* arrtype); fir::Function* getReserveExtraFunction(CodegenState* cs, fir::DynamicArrayType* arrtype); fir::Function* getReserveAtLeastFunction(CodegenState* cs, fir::DynamicArrayType* arrtype); fir::Function* getSetElementsToValueFunction(CodegenState* cs, fir::Type* elmType); fir::Function* getSetElementsToDefaultValueFunction(CodegenState* cs, fir::Type* elmType); fir::Function* getCallClassConstructorOnElementsFunction(CodegenState* cs, fir::ClassType* cls, sst::FunctionDefn* constr, const std::vector& args); } namespace saa_common { fir::Function* generateCloneFunction(CodegenState* cs, fir::Type* saa); fir::Function* generateAppendFunction(CodegenState* cs, fir::Type* saa); fir::Function* generateElementAppendFunction(CodegenState* cs, fir::Type* saa); fir::Function* generateConstructFromTwoFunction(CodegenState* cs, fir::Type* saa); fir::Function* generateConstructWithElementFunction(CodegenState* cs, fir::Type* saa); fir::Function* generateAppropriateAppendFunction(CodegenState* cs, fir::Type* saa, fir::Type* appendee); fir::Function* generateBoundsCheckFunction(CodegenState* cs, bool isstring, bool isDecomp); fir::Function* generateReserveExtraFunction(CodegenState* cs, fir::Type* saa); fir::Function* generateReserveAtLeastFunction(CodegenState* cs, fir::Type* saa); fir::Value* makeNewRefCountPointer(CodegenState* cs, fir::Value* rc); fir::Value* initSAAWithRefCount(CodegenState* cs, fir::Value* str, fir::Value* rc); } namespace any { fir::Function* getRefCountIncrementFunction(CodegenState* cs); fir::Function* getRefCountDecrementFunction(CodegenState* cs); fir::Function* generateCreateAnyWithValueFunction(CodegenState* cs, fir::Type* type); fir::Function* generateGetValueFromAnyFunction(CodegenState* cs, fir::Type* type); } namespace misc { fir::Function* getMallocWrapperFunction(CodegenState* cs); fir::Function* getRangeSanityCheckFunction(CodegenState* cs); fir::Name getCompare_FName(fir::Type* t); fir::Name getSetElements_FName(fir::Type* t); fir::Name getSetElementsDefault_FName(fir::Type* t); fir::Name getCallClassConstructor_FName(fir::Type* t); fir::Name getClone_FName(fir::Type* t); fir::Name getAppend_FName(fir::Type* t); fir::Name getPopBack_FName(fir::Type* t); fir::Name getMakeFromTwo_FName(fir::Type* t); fir::Name getMakeFromOne_FName(fir::Type* t); fir::Name getReserveExtra_FName(fir::Type* t); fir::Name getAppendElement_FName(fir::Type* t); fir::Name getReserveEnough_FName(fir::Type* t); fir::Name getRecursiveRefcount_FName(fir::Type* t, bool incr); fir::Name getIncrRefcount_FName(fir::Type* t); fir::Name getDecrRefcount_FName(fir::Type* t); fir::Name getLoopIncrRefcount_FName(fir::Type* t); fir::Name getLoopDecrRefcount_FName(fir::Type* t); fir::Name getCreateAnyOf_FName(fir::Type* t); fir::Name getGetValueFromAny_FName(fir::Type* t); fir::Name getBoundsCheck_FName(); fir::Name getDecompBoundsCheck_FName(); fir::Name getMallocWrapper_FName(); fir::Name getRangeSanityCheck_FName(); fir::Name getUtf8Length_FName(); } } } ================================================ FILE: source/include/ir/block.h ================================================ // block.h // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include #include #include #include "value.h" #include "instruction.h" namespace fir { struct Function; struct IRBuilder; struct IRBlock : Value { friend struct Module; friend struct IRBuilder; IRBlock(); IRBlock(Function* parentFunc); Function* getParentFunction(); void setFunction(Function* fn); void addInstruction(Instruction* inst); void eraseFromParentFunction(); bool isTerminated(); std::vector& getInstructions(); private: Function* parentFunction = 0; std::vector instructions; }; } ================================================ FILE: source/include/ir/constant.h ================================================ // constant.h // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include #include #include #include "value.h" #include "mpreal/mpreal.h" namespace fir { struct Value; struct ConstantValue; // base class implicitly stores null struct ConstantValue : Value { friend struct Module; friend struct IRBuilder; // static stuff static ConstantValue* getZeroValue(Type* type); static ConstantValue* getNull(); virtual std::string str(); protected: ConstantValue(Type* type); }; struct ConstantNumber : ConstantValue { friend struct Module; static ConstantNumber* get(ConstantNumberType* cnt, const mpfr::mpreal& n); int8_t getInt8() { return static_cast(this->number.toLLong()); } int16_t getInt16() { return static_cast(this->number.toLLong()); } int32_t getInt32() { return static_cast(this->number.toLLong()); } int64_t getInt64() { return static_cast(this->number.toLLong()); } uint8_t getUint8() { return static_cast(this->number.toULLong()); } uint16_t getUint16() { return static_cast(this->number.toULLong()); } uint32_t getUint32() { return static_cast(this->number.toULLong()); } uint64_t getUint64() { return static_cast(this->number.toULLong()); } float getFloat() { return this->number.toFloat(); } double getDouble() { return this->number.toDouble(); } virtual std::string str() override; protected: ConstantNumber(ConstantNumberType* cnt, const mpfr::mpreal& n); mpfr::mpreal number; }; struct ConstantBool : ConstantValue { friend struct Module; static ConstantBool* get(bool value); bool getValue(); virtual std::string str() override; protected: ConstantBool(bool val); bool value; }; struct ConstantInt : ConstantValue { friend struct Module; static ConstantInt* get(Type* intType, uint64_t val); static ConstantInt* getInt8(int8_t value); static ConstantInt* getInt16(int16_t value); static ConstantInt* getInt32(int32_t value); static ConstantInt* getInt64(int64_t value); static ConstantInt* getUint8(uint8_t value); static ConstantInt* getUint16(uint16_t value); static ConstantInt* getUint32(uint32_t value); static ConstantInt* getUint64(uint64_t value); static ConstantInt* getNative(int64_t value); static ConstantInt* getUNative(uint64_t value); int64_t getSignedValue(); uint64_t getUnsignedValue(); virtual std::string str() override; protected: ConstantInt(Type* type, int64_t val); ConstantInt(Type* type, uint64_t val); uint64_t value; }; struct ConstantFP : ConstantValue { friend struct Module; static ConstantFP* get(Type* intType, float val); static ConstantFP* get(Type* intType, double val); static ConstantFP* getFloat32(float value); static ConstantFP* getFloat64(double value); double getValue(); virtual std::string str() override; protected: ConstantFP(Type* type, float val); ConstantFP(Type* type, double val); double value; }; struct ConstantArray : ConstantValue { friend struct Module; static ConstantArray* get(Type* type, const std::vector& vals); std::vector getValues() { return this->values; } virtual std::string str() override; protected: ConstantArray(Type* type, const std::vector& vals); std::vector values; }; struct ConstantStruct : ConstantValue { friend struct Module; static ConstantStruct* get(StructType* st, const std::vector& members); virtual std::string str() override; protected: ConstantStruct(StructType* st, const std::vector& members); std::vector members; }; struct ConstantEnumCase : ConstantValue { friend struct Module; static ConstantEnumCase* get(EnumType* en, ConstantInt* index, ConstantValue* value); ConstantInt* getIndex(); ConstantValue* getValue(); virtual std::string str() override; protected: ConstantEnumCase(EnumType* en, ConstantInt* index, ConstantValue* value); ConstantInt* index = 0; ConstantValue* value = 0; }; struct ConstantCharSlice : ConstantValue { friend struct Module; static ConstantCharSlice* get(const std::string& value); std::string getValue(); virtual std::string str() override; protected: ConstantCharSlice(const std::string& str); std::string value; }; struct ConstantTuple : ConstantValue { friend struct Module; static ConstantTuple* get(const std::vector& mems); std::vector getValues(); virtual std::string str() override; protected: ConstantTuple(const std::vector& mems); std::vector values; }; struct ConstantDynamicArray : ConstantValue { friend struct Module; static ConstantDynamicArray* get(DynamicArrayType* type, ConstantValue* data, ConstantValue* length, ConstantValue* capacity); static ConstantDynamicArray* get(ConstantArray* arr); ConstantValue* getData() { return this->data; } ConstantValue* getLength() { return this->length; } ConstantValue* getCapacity() { return this->capacity; } ConstantArray* getArray() { return this->arr; } virtual std::string str() override; protected: ConstantDynamicArray(DynamicArrayType* type); ConstantValue* data = 0; ConstantValue* length = 0; ConstantValue* capacity = 0; ConstantArray* arr = 0; }; // this is the 'string' type!! struct ConstantDynamicString : ConstantValue { friend struct Module; static ConstantDynamicString* get(const std::string& s); std::string getValue(); virtual std::string str() override; protected: ConstantDynamicString(const std::string& s); std::string value; }; struct ConstantArraySlice : ConstantValue { friend struct Module; static ConstantArraySlice* get(ArraySliceType* type, ConstantValue* data, ConstantValue* length); ConstantValue* getData() { return this->data; } ConstantValue* getLength() { return this->length; } virtual std::string str() override; protected: ConstantArraySlice(ArraySliceType* type); ConstantValue* data = 0; ConstantValue* length = 0; }; struct ConstantBitcast : ConstantValue { friend struct Module; static ConstantBitcast* get(ConstantValue* v, Type* target); ConstantValue* getValue() { return this->value; } virtual std::string str() override; protected: ConstantBitcast(ConstantValue* v, Type* target); ConstantValue* value = 0; Type* target = 0; }; struct GlobalValue : ConstantValue { friend struct Module; LinkageType linkageType; Module* getParentModule() { return this->parentModule; } virtual std::string str() override; protected: GlobalValue(Module* mod, Type* type, LinkageType linkage, bool mut = false); Module* parentModule = 0; }; struct GlobalVariable : GlobalValue { friend struct Module; GlobalVariable(const Name& idt, Module* module, Type* type, bool immutable, LinkageType linkage, ConstantValue* initValue); void setInitialValue(ConstantValue* constVal); ConstantValue* getInitialValue(); virtual std::string str() override; protected: ConstantValue* initValue = 0; }; } ================================================ FILE: source/include/ir/function.h ================================================ // function.h // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include #include #include #include "block.h" #include "constant.h" namespace fir { struct Function; struct IRBuilder; struct Argument : Value { friend struct Function; friend struct IRBuilder; // virtual stuff // default: virtual Type* getType() // methods Argument(Function* fn, Type* type); ~Argument(); Value* getActualValue(); Function* getParentFunction(); void setValue(Value* v); void clearValue(); // fields protected: Function* parentFunction; Value* realValue = 0; }; struct Function : GlobalValue { friend struct Module; friend struct Argument; friend struct IRBuilder; bool isCStyleVarArg(); bool isVariadic(); Type* getReturnType(); size_t getArgumentCount(); const std::vector& getArguments(); Argument* getArgumentWithName(std::string name); std::vector& getBlockList(); void deleteBody(); bool wasDeclaredWithBodyElsewhere(); void setHadBodyElsewhere(); bool isAlwaysInlined(); void setAlwaysInline(); bool isIntrinsicFunction(); void setIsIntrinsic(); // this is used so the function knows how much space it needs to reserve for // allocas. void addStackAllocation(Type* ty); const std::vector& getStackAllocations(); void cullUnusedValues(); // overridden stuff virtual FunctionType* getType() override; // override because better (more specific) return type. static Function* create(const Name& name, FunctionType* fnType, Module* module, LinkageType linkage); // fields protected: Function(const Name& name, FunctionType* fnType, Module* module, LinkageType linkage); std::vector fnArguments; std::vector blocks; std::vector stackAllocs; bool alwaysInlined = false; bool hadBodyElsewhere = false; bool fnIsIntrinsicFunction = false; }; } ================================================ FILE: source/include/ir/instruction.h ================================================ // instruction.h // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include #include #include #include "value.h" namespace fir { enum class OpKind { Invalid, // signed Signed_Add, Signed_Sub, Signed_Mul, Signed_Div, Signed_Mod, Signed_Neg, // unsigned Unsigned_Add, Unsigned_Sub, Unsigned_Mul, Unsigned_Div, Unsigned_Mod, // floating point Floating_Add, Floating_Sub, Floating_Mul, Floating_Div, Floating_Mod, Floating_Neg, Floating_Truncate, Floating_Extend, // comparison ICompare_Equal, ICompare_NotEqual, ICompare_Greater, ICompare_Less, ICompare_GreaterEqual, ICompare_LessEqual, ICompare_Multi, FCompare_Multi, FCompare_Equal_ORD, FCompare_Equal_UNORD, FCompare_NotEqual_ORD, FCompare_NotEqual_UNORD, FCompare_Greater_ORD, FCompare_Greater_UNORD, FCompare_Less_ORD, FCompare_Less_UNORD, FCompare_GreaterEqual_ORD, FCompare_GreaterEqual_UNORD, FCompare_LessEqual_ORD, FCompare_LessEqual_UNORD, // bitwise Bitwise_Not, Bitwise_Xor, Bitwise_Arithmetic_Shr, Bitwise_Logical_Shr, Bitwise_Shl, Bitwise_And, Bitwise_Or, // casting Cast_Bitcast, Cast_IntSize, Cast_Signedness, Cast_FloatToInt, Cast_IntToFloat, Cast_PointerType, Cast_PointerToInt, Cast_IntToPointer, Cast_IntSignedness, Integer_ZeroExt, Integer_Truncate, // unary Logical_Not, // values Value_ReadPtr, Value_WritePtr, Value_StackAlloc, Value_CallFunction, Value_CallFunctionPointer, Value_CallVirtualMethod, Value_Return, Value_GetPointerToStructMember, // equivalent to GEP(ptr*, ptrIndex, memberIndex) -- for structs. Value_GetStructMember, // equivalent to GEP(ptr*, 0, memberIndex) Value_GetPointer, // equivalent to GEP(ptr*, index) Value_GetGEP2, // equivalent to GEP(ptr*, ptrIndex, elmIndex) -- for arrays/pointers Value_InsertValue, // corresponds to llvm. Value_ExtractValue, // same Value_Select, // same as llvm: takes 3 operands, the first being a bool and the others being a condition. // if the bool == true, returns the first value, else returns the second. Value_CreatePHI, Misc_Sizeof, // portable sizeof using GEP Value_Dereference, Value_AddressOf, Value_Store, Value_CreateLVal, // string-specific things SAA_GetData, SAA_SetData, SAA_GetLength, SAA_SetLength, SAA_GetCapacity, SAA_SetCapacity, SAA_GetRefCountPtr, SAA_SetRefCountPtr, ArraySlice_GetData, ArraySlice_SetData, ArraySlice_GetLength, ArraySlice_SetLength, Any_GetData, Any_SetData, Any_GetTypeID, Any_SetTypeID, Any_GetRefCountPtr, Any_SetRefCountPtr, Range_GetLower, Range_SetLower, Range_GetUpper, Range_SetUpper, Range_GetStep, Range_SetStep, Enum_GetIndex, Enum_SetIndex, Enum_GetValue, Enum_SetValue, Union_SetValue, Union_GetValue, Union_GetVariantID, Union_SetVariantID, RawUnion_GEP, Branch_UnCond, Branch_Cond, Unreachable, }; struct IRBuilder; struct Instruction : Value { friend struct Module; friend struct IRBuilder; Instruction(OpKind kind, bool sideEffects, Type* out, const std::vector& vals); Instruction(OpKind kind, bool sideEffects, Type* out, const std::vector& vals, Value::Kind k); std::string str(); Value* getResult(); void setValue(Value* v); void clearValue(); bool hasSideEffects(); // static Instruction* GetBinaryOpInstruction(Ast::ArithmeticOp ao, Value* lhs, Value* rhs); // protected: OpKind opKind; bool sideEffects; Value* realOutput; std::vector operands; }; } ================================================ FILE: source/include/ir/interp.h ================================================ // interp.h // Copyright (c) 2017, zhiayang@gmail.com // Licensed under the Apache License Version 2.0. #pragma once #include #include #include #include #include namespace fir { struct Type; struct Value; struct Module; struct IRBlock; struct Function; struct GlobalValue; struct ConstantValue; namespace interp { //? is it bad form to name these the same as our fir structs?? struct Value { fir::Value* val = 0; fir::Type* type = 0; size_t dataSize = 0; union { void* ptr; uint8_t data[32]; }; // kinda a dirty hack, we need to know whether or not to write-back the global after the interpreter // is done, cases where we modify stuff during compile-time execution. of course, the real value could // be *derived* from a global, eg. a GEP on a struct, or something. so, we persistently tag it. fir::GlobalValue* globalValTracker = 0; }; struct Instruction { size_t opcode; fir::Value* result = 0; std::vector args; }; struct Block { fir::IRBlock* blk = 0; std::vector instructions; }; struct Function { fir::Function* func = 0; bool isExternal = false; std::string extFuncName; interp::Block* entryBlock = 0; std::vector blocks; }; struct InterpState { InterpState(fir::Module* mod); ~InterpState(); void initialise(bool runGlobalInit); void finalise(); interp::Function& compileFunction(fir::Function* fn); interp::Value runFunction(const interp::Function& fn, const std::vector& args); interp::Value makeValue(fir::Value* ty); fir::ConstantValue* unwrapInterpValueIntoConstant(const interp::Value& val); struct Frame { size_t currentInstrIndex = 0; const interp::Block* currentBlock = 0; const interp::Block* previousBlock = 0; const interp::Function* currentFunction = 0; std::vector stackAllocs; fir::Value* callResultOutput = 0; std::unordered_map values; }; // this is the executing state. std::vector stackFrames; std::unordered_map> globals; std::vector globalAllocs; std::vector strings; // map from the id to the real function. // we don't want 'inheritance' here std::unordered_map compiledFunctions; fir::Module* module = 0; }; } } ================================================ FILE: source/include/ir/irbuilder.h ================================================ // irbuilder.h // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include #include #include #include "block.h" #include "value.h" #include "module.h" #include "function.h" #include "constant.h" namespace fir { struct IRBuilder { IRBuilder(Module* mod); Value* Negate(Value* a, const std::string& vname = ""); Value* Add(Value* a, Value* b, const std::string& vname = ""); Value* Subtract(Value* a, Value* b, const std::string& vname = ""); Value* Multiply(Value* a, Value* b, const std::string& vname = ""); Value* Divide(Value* a, Value* b, const std::string& vname = ""); Value* Modulo(Value* a, Value* b, const std::string& vname = ""); Value* ICmpEQ(Value* a, Value* b, const std::string& vname = ""); Value* ICmpNEQ(Value* a, Value* b, const std::string& vname = ""); Value* ICmpGT(Value* a, Value* b, const std::string& vname = ""); Value* ICmpLT(Value* a, Value* b, const std::string& vname = ""); Value* ICmpGEQ(Value* a, Value* b, const std::string& vname = ""); Value* ICmpLEQ(Value* a, Value* b, const std::string& vname = ""); Value* FCmpEQ_ORD(Value* a, Value* b, const std::string& vname = ""); Value* FCmpEQ_UNORD(Value* a, Value* b, const std::string& vname = ""); Value* FCmpNEQ_ORD(Value* a, Value* b, const std::string& vname = ""); Value* FCmpNEQ_UNORD(Value* a, Value* b, const std::string& vname = ""); Value* FCmpGT_ORD(Value* a, Value* b, const std::string& vname = ""); Value* FCmpGT_UNORD(Value* a, Value* b, const std::string& vname = ""); Value* FCmpLT_ORD(Value* a, Value* b, const std::string& vname = ""); Value* FCmpLT_UNORD(Value* a, Value* b, const std::string& vname = ""); Value* FCmpGEQ_ORD(Value* a, Value* b, const std::string& vname = ""); Value* FCmpGEQ_UNORD(Value* a, Value* b, const std::string& vname = ""); Value* FCmpLEQ_ORD(Value* a, Value* b, const std::string& vname = ""); Value* FCmpLEQ_UNORD(Value* a, Value* b, const std::string& vname = ""); Value* ICmpMulti(Value* a, Value* b, const std::string& vname = ""); Value* FCmpMulti(Value* a, Value* b, const std::string& vname = ""); Value* BitwiseXOR(Value* a, Value* b, const std::string& vname = ""); Value* BitwiseLogicalSHR(Value* a, Value* b, const std::string& vname = ""); Value* BitwiseArithmeticSHR(Value* a, Value* b, const std::string& vname = ""); Value* BitwiseSHL(Value* a, Value* b, const std::string& vname = ""); Value* BitwiseAND(Value* a, Value* b, const std::string& vname = ""); Value* BitwiseOR(Value* a, Value* b, const std::string& vname = ""); Value* BitwiseNOT(Value* a, const std::string& vname = ""); Value* Bitcast(Value* v, Type* targetType, const std::string& vname = ""); Value* IntSizeCast(Value* v, Type* targetType, const std::string& vname = ""); Value* FloatToIntCast(Value* v, Type* targetType, const std::string& vname = ""); Value* IntToFloatCast(Value* v, Type* targetType, const std::string& vname = ""); Value* PointerTypeCast(Value* v, Type* targetType, const std::string& vname = ""); Value* PointerToIntCast(Value* v, Type* targetType, const std::string& vname = ""); Value* IntToPointerCast(Value* v, Type* targetType, const std::string& vname = ""); Value* IntSignednessCast(Value* v, Type* targetType, const std::string& vname = ""); Value* AppropriateCast(Value* v, Type* targetType, const std::string& vname = ""); Value* IntTruncate(Value* v, Type* targetType, const std::string& vname = ""); Value* IntZeroExt(Value* v, Type* targetType, const std::string& vname = ""); Value* FTruncate(Value* v, Type* targetType, const std::string& vname = ""); Value* FExtend(Value* v, Type* targetType, const std::string& vname = ""); Value* Call(Function* fn, const std::string& vname = ""); Value* Call(Function* fn, Value* p1, const std::string& vname = ""); Value* Call(Function* fn, Value* p1, Value* p2, const std::string& vname = ""); Value* Call(Function* fn, Value* p1, Value* p2, Value* p3, const std::string& vname = ""); Value* Call(Function* fn, Value* p1, Value* p2, Value* p3, Value* p4, const std::string& vname = ""); Value* Call(Function* fn, const std::vector& args, const std::string& vname = ""); Value* Call(Function* fn, const std::initializer_list& args, const std::string& vname = ""); Value* CallToFunctionPointer(Value* fn, FunctionType* ft, const std::vector& args, const std::string& vname = ""); Value* CallVirtualMethod(ClassType* cls, FunctionType* ft, size_t index, const std::vector& args, const std::string& vname = ""); Value* Return(Value* v); Value* ReturnVoid(); Value* LogicalNot(Value* v, const std::string& vname = ""); PHINode* CreatePHINode(Type* type, const std::string& vname = ""); Value* StackAlloc(Type* type, const std::string& vname = ""); Value* ImmutStackAlloc(Type* type, Value* initialValue, const std::string& vname = ""); // given an l or cl value of raw_union type, return an l or cl value of the correct type of the field Value* GetRawUnionField(Value* lval, const std::string& field, const std::string& vname = ""); // same as the above, but give it a type instead -- this is hacky cos it's not checked. // the backend will just do some pointer magic regardless, so it doesn't really matter. Value* GetRawUnionFieldByType(Value* lval, Type* type, const std::string& vname = ""); // equivalent to GEP(ptr*, 0, memberIndex) Value* GetStructMember(Value* ptr, const std::string& memberName); Value* StructGEP(Value* structPtr, size_t memberIndex, const std::string& vname = ""); // equivalent to GEP(ptr*, index) Value* GetPointer(Value* ptr, Value* ptrIndex, const std::string& vname = ""); // equivalent to GEP(ptr*, ptrIndex, elmIndex) Value* GEP2(Value* ptr, Value* ptrIndex, Value* elmIndex, const std::string& vname = ""); Value* ConstGEP2(Value* ptr, size_t ptrIndex, size_t elmIndex, const std::string& vname = ""); void SetVtable(Value* ptr, Value* table); void CondBranch(Value* condition, IRBlock* trueBlock, IRBlock* falseBlock); void UnCondBranch(IRBlock* target); Value* Sizeof(Type* t, const std::string& vname = ""); Value* Select(Value* cond, Value* one, Value* two, const std::string& vname = ""); Value* BinaryOp(const std::string& ao, Value* a, Value* b, const std::string& vname = ""); Value* CreateValue(Type* t, const std::string& vname = ""); Value* ExtractValue(Value* val, const std::vector& inds, const std::string& vname = ""); Value* ExtractValueByName(Value* val, const std::string& mem, const std::string& vname = ""); [[nodiscard]] Value* InsertValueByName(Value* val, const std::string& mem, Value* elm, const std::string& vname = ""); [[nodiscard]] Value* InsertValue(Value* val, const std::vector& inds, Value* elm, const std::string& vname = ""); //! ACHTUNG ! //* 'generic' function that works for both strings and dynamic arrays, //* since they now function almost exactly the same. //? SAA -- String Array Analogue Value* GetSAAData(Value* str, const std::string& vname = ""); Value* GetSAALength(Value* str, const std::string& vname = ""); Value* GetSAACapacity(Value* str, const std::string& vname = ""); Value* GetSAARefCount(Value* str, const std::string& vname = ""); Value* GetSAARefCountPointer(Value* str, const std::string& vname = ""); [[nodiscard]] Value* SetSAARefCountPointer(Value* str, Value* val, const std::string& vname = ""); [[nodiscard]] Value* SetSAACapacity(Value* str, Value* val, const std::string& vname = ""); [[nodiscard]] Value* SetSAALength(Value* str, Value* val, const std::string& vname = ""); [[nodiscard]] Value* SetSAAData(Value* str, Value* val, const std::string& vname = ""); void SetSAARefCount(Value* str, Value* val); Value* CreateSliceFromSAA(Value* str, bool mut, const std::string& vname = ""); Value* GetArraySliceData(Value* arr, const std::string& vname = ""); Value* GetArraySliceLength(Value* arr, const std::string& vname = ""); [[nodiscard]] Value* SetArraySliceData(Value* arr, Value* val, const std::string& vname = ""); [[nodiscard]] Value* SetArraySliceLength(Value* arr, Value* val, const std::string& vname = ""); Value* GetAnyData(Value* any, const std::string& vname = ""); Value* GetAnyTypeID(Value* any, const std::string& vname = ""); Value* GetAnyRefCount(Value* str, const std::string& vname = ""); Value* GetAnyRefCountPointer(Value* any, const std::string& vname = ""); void SetAnyRefCount(Value* str, Value* val); [[nodiscard]] Value* SetAnyData(Value* any, Value* val, const std::string& vname = ""); [[nodiscard]] Value* SetAnyTypeID(Value* any, Value* val, const std::string& vname = ""); [[nodiscard]] Value* SetAnyRefCountPointer(Value* str, Value* val, const std::string& vname = ""); Value* GetRangeLower(Value* range, const std::string& vname = ""); Value* GetRangeUpper(Value* range, const std::string& vname = ""); Value* GetRangeStep(Value* range, const std::string& vname = ""); [[nodiscard]] Value* SetRangeLower(Value* range, Value* val, const std::string& vname = ""); [[nodiscard]] Value* SetRangeUpper(Value* range, Value* val, const std::string& vname = ""); [[nodiscard]] Value* SetRangeStep(Value* range, Value* step, const std::string& vname = ""); Value* GetEnumCaseIndex(Value* ecs, const std::string& vname = ""); Value* GetEnumCaseValue(Value* ecs, const std::string& vname = ""); [[nodiscard]] Value* SetEnumCaseIndex(Value* ecs, Value* idx, const std::string& vname = ""); [[nodiscard]] Value* SetEnumCaseValue(Value* ecs, Value* val, const std::string& vname = ""); [[nodiscard]] Value* SetUnionVariantData(Value* unn, size_t id, Value* data, const std::string& vname = ""); [[nodiscard]] Value* GetUnionVariantData(Value* unn, size_t id, const std::string& vname = ""); [[nodiscard]] Value* GetUnionVariantID(Value* unn, const std::string& vname = ""); [[nodiscard]] Value* SetUnionVariantID(Value* unn, size_t id, const std::string& vname = ""); //* V2 api Value* ReadPtr(Value* ptr, const std::string& vname = ""); void WritePtr(Value* v, Value* ptr); void Store(Value* val, Value* lval); Value* CreateLValue(Type* t, const std::string& vname = ""); Value* Dereference(Value* val, const std::string& vname = ""); Value* AddressOf(Value* lval, bool mut, const std::string& vname = ""); void Unreachable(); IRBlock* addNewBlockInFunction(const std::string& name, Function* func); IRBlock* addNewBlockAfter(const std::string& name, IRBlock* block); void setCurrentBlock(IRBlock* block); void restorePreviousBlock(); Function* getCurrentFunction(); IRBlock* getCurrentBlock(); private: Value* addInstruction(Instruction* instr, const std::string& vname); Module* module = 0; Function* currentFunction = 0; IRBlock* currentBlock = 0; IRBlock* previousBlock = 0; }; } ================================================ FILE: source/include/ir/module.h ================================================ // module.h // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include #include #include #include "value.h" #include "function.h" namespace fir { struct Module { friend struct GlobalValue; friend struct GlobalVariable; Module(const std::string& nm); GlobalVariable* createGlobalVariable(const Name& id, Type* type, ConstantValue* initVal, bool isImmut, LinkageType linkage); GlobalVariable* createGlobalVariable(const Name& id, Type* type, bool isImmut, LinkageType linkage); GlobalVariable* declareGlobalVariable(const Name& id, Type* type, bool isImmut); GlobalVariable* tryGetGlobalVariable(const Name& id); GlobalVariable* getGlobalVariable(const Name& id); GlobalVariable* getOrCreateVirtualTableForClass(ClassType* cls); GlobalVariable* createGlobalString(const std::string& str); std::vector getGlobalVariables(); std::vector getAllFunctions(); std::vector getNamedTypes(); // note: only looks at the name + scope, excludes the parameter list. std::vector getFunctionsWithName(const Name& id); Function* getIntrinsicFunction(const std::string& id); Type* getNamedType(const Name& name); void addNamedType(const Name& name, Type* type); void addFunction(Function* func); void removeFunction(Function* func); Function* declareFunction(const Name& id, FunctionType* ftype); Function* getFunction(const Name& id); Function* getOrCreateFunction(const Name& id, FunctionType* ftype, LinkageType linkage); std::string getModuleName(); void setModuleName(const std::string& name); std::string print(); Function* getEntryFunction(); void setEntryFunction(Function* fn); void finaliseGlobalConstructors(); const util::hash_map, GlobalVariable*>>& _getVtables() { return this->vtables; } const util::hash_map& _getIntrinsicFunctions() { return this->intrinsicFunctions; } const util::hash_map& _getGlobalStrings() { return this->globalStrings; } const util::hash_map& _getGlobals() { return this->globals; } const util::hash_map& _getFunctions() { return this->functions; } const util::hash_map& _getNamedTypes() { return this->namedTypes; } private: std::string moduleName; util::hash_map, GlobalVariable*>> vtables; util::hash_map globalStrings; util::hash_map globals; util::hash_map functions; util::hash_map namedTypes; util::hash_map intrinsicFunctions; Function* entryFunction = 0; }; } ================================================ FILE: source/include/ir/type.h ================================================ // type.h // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include "defs.h" #include "precompile.h" namespace fir { enum class NameKind { Name, Type, Function }; struct Type; struct Name { NameKind kind; std::string name; std::vector scope; std::vector params; fir::Type* retty; std::string str() const; std::string mangled() const; std::string mangledWithoutScope() const; bool operator== (const Name& other) const; bool operator!= (const Name& other) const; static Name of(std::string name); static Name of(std::string name, std::vector scope); static Name type(std::string name); static Name type(std::string name, std::vector scope); static Name function(std::string name, std::vector params, fir::Type* retty); static Name function(std::string name, std::vector scope, std::vector params, fir::Type* retty); static Name obfuscate(const std::string& name, NameKind kind = NameKind::Name); static Name obfuscate(const std::string& name, size_t id, NameKind kind = NameKind::Name); static Name obfuscate(const std::string& name, const std::string& extra, NameKind kind = NameKind::Name); private: Name(NameKind kind, std::string name, std::vector scope, std::vector params, fir::Type* retty) : kind(kind), name(std::move(name)), scope(std::move(scope)), params(std::move(params)), retty(retty) { } }; std::string obfuscateName(const std::string& name); std::string obfuscateName(const std::string& name, size_t id); std::string obfuscateName(const std::string& name, const std::string& extra); } template <> struct zpr::print_formatter { std::string print(const fir::Name& x, const format_args& args); }; namespace std { template<> struct hash { std::size_t operator()(const fir::Name& k) const { using std::size_t; using std::hash; using std::string; // Compute individual hash values for first, // second and third and combine them using XOR // and bit shifting: // return ((hash()(k.name) ^ (hash>()(k.scope) << 1)) >> 1) ^ (hash()(k.third) << 1); return hash()(k.str()); } }; } namespace fir { // NOTE: i don't really want to deal with inheritance stuff right now, // so Type will encapsulate everything. // we shouldn't be making any copies anyway, so space/performance is a negligible concern struct Type; struct Module; struct AnyType; struct BoolType; struct EnumType; struct NullType; struct VoidType; struct ArrayType; struct ClassType; struct RangeType; struct TraitType; struct TupleType; struct UnionType; struct StringType; struct StructType; struct OpaqueType; struct PointerType; struct FunctionType; struct RawUnionType; struct PrimitiveType; struct ArraySliceType; struct DynamicArrayType; struct UnionVariantType; struct ConstantNumberType; struct PolyPlaceholderType; struct ConstantValue; struct ConstantArray; struct Function; ConstantNumberType* unifyConstantTypes(ConstantNumberType* a, ConstantNumberType* b); Type* getBestFitTypeForConstant(ConstantNumberType* cnt); int getCastDistance(Type* from, Type* to); bool isRefCountedType(Type* ty); void setNativeWordSizeInBits(size_t sz); size_t getNativeWordSizeInBits(); // in theory. size_t getSizeOfType(Type* type); size_t getAlignmentOfType(Type* type); bool areTypesCovariant(Type* base, Type* derv); bool areTypesContravariant(Type* base, Type* derv, bool traitChecking); bool areMethodsVirtuallyCompatible(FunctionType* base, FunctionType* fn, bool traitChecking); bool areTypeListsContravariant(const std::vector& base, const std::vector& derv, bool traitChecking); enum class TypeKind { Invalid, Any, Null, Void, Enum, Bool, Array, Tuple, Class, Range, Union, Trait, Struct, String, Opaque, Pointer, Function, RawUnion, Primitive, ArraySlice, DynamicArray, UnionVariant, ConstantNumber, PolyPlaceholder, }; struct Type { // stuff static Type* fromBuiltin(const std::string& builtin); static std::string typeListToString(const std::vector& types, bool includeBraces = false); static std::string typeListToString(const std::initializer_list& types, bool includeBraces = false); static bool areTypeListsEqual(const std::vector& a, const std::vector& b); static bool areTypeListsEqual(const std::initializer_list& a, const std::initializer_list& b); // various virtual std::string str() = 0; virtual std::string encodedStr() = 0; virtual bool isTypeEqual(Type* other) = 0; virtual Type* substitutePlaceholders(const util::hash_map& subst) = 0; Type* getPointerTo(); Type* getMutablePointerTo(); Type* getPointerElementType(); Type* getMutablePointerVersion(); Type* getImmutablePointerVersion(); // note: works for all array types, be it dynamic, fixed, or slices Type* getArrayElementType(); PolyPlaceholderType* toPolyPlaceholderType(); ConstantNumberType* toConstantNumberType(); DynamicArrayType* toDynamicArrayType(); UnionVariantType* toUnionVariantType(); ArraySliceType* toArraySliceType(); PrimitiveType* toPrimitiveType(); RawUnionType* toRawUnionType(); FunctionType* toFunctionType(); PointerType* toPointerType(); OpaqueType* toOpaqueType(); StructType* toStructType(); StringType* toStringType(); TraitType* toTraitType(); RangeType* toRangeType(); ClassType* toClassType(); UnionType* toUnionType(); TupleType* toTupleType(); ArrayType* toArrayType(); BoolType* toBoolType(); EnumType* toEnumType(); NullType* toNullType(); AnyType* toAnyType(); bool isPointerTo(Type* other); bool isPointerElementOf(Type* other); bool isTraitType(); bool isUnionType(); bool isTupleType(); bool isClassType(); bool isStructType(); bool isPackedStruct(); bool isRawUnionType(); bool isUnionVariantType(); bool isRangeType(); bool isCharType(); bool isStringType(); bool isOpaqueType(); bool isAnyType(); bool isEnumType(); bool isArrayType(); bool isIntegerType(); bool isFunctionType(); bool isSignedIntType(); bool isUnsignedIntType(); bool isFloatingPointType(); bool isArraySliceType(); bool isDynamicArrayType(); bool isVariadicArrayType(); bool isCharSliceType(); bool isPrimitiveType(); bool isPointerType(); bool isVoidType(); bool isNullType(); bool isBoolType(); bool isMutablePointer(); bool isImmutablePointer(); bool isConstantNumberType(); bool isPolyPlaceholderType(); bool containsPlaceholders(); std::vector getContainedPlaceholders(); size_t getBitWidth(); Type* getIndirectedType(int times); size_t getID() { return this->id; } // convenience static VoidType* getVoid(); static NullType* getNull(); static Type* getVoidPtr(); static BoolType* getBool(); static PrimitiveType* getInt8(); static PrimitiveType* getInt16(); static PrimitiveType* getInt32(); static PrimitiveType* getInt64(); static PrimitiveType* getInt128(); static PrimitiveType* getUint8(); static PrimitiveType* getUint16(); static PrimitiveType* getUint32(); static PrimitiveType* getUint64(); static PrimitiveType* getUint128(); static PrimitiveType* getFloat32(); static PrimitiveType* getFloat64(); static PrimitiveType* getFloat128(); static PointerType* getInt8Ptr(); static PointerType* getInt16Ptr(); static PointerType* getInt32Ptr(); static PointerType* getInt64Ptr(); static PointerType* getInt128Ptr(); static PointerType* getUint8Ptr(); static PointerType* getUint16Ptr(); static PointerType* getUint32Ptr(); static PointerType* getUint64Ptr(); static PointerType* getUint128Ptr(); static PointerType* getMutInt8Ptr(); static PointerType* getMutInt16Ptr(); static PointerType* getMutInt32Ptr(); static PointerType* getMutInt64Ptr(); static PointerType* getMutInt128Ptr(); static PointerType* getMutUint8Ptr(); static PointerType* getMutUint16Ptr(); static PointerType* getMutUint32Ptr(); static PointerType* getMutUint64Ptr(); static PointerType* getMutUint128Ptr(); static ArraySliceType* getCharSlice(bool mut); static StringType* getString(); static RangeType* getRange(); static AnyType* getAny(); static PrimitiveType* getNativeWord(); static PrimitiveType* getNativeUWord(); static PointerType* getNativeWordPtr(); virtual ~Type() { } const TypeKind kind; protected: Type(TypeKind k) : kind(k) { static size_t __id = 0; this->id = __id++; } // base things size_t id = 0; PointerType* pointerTo = 0; PointerType* mutablePointerTo = 0; static Type* getOrCreateFloatingTypeWithConstraints(size_t bits); static Type* getOrCreateIntegerTypeWithConstraints(bool issigned, size_t bits); static Type* getOrCreateArrayTypeWithConstraints(size_t arrsize, Type* elm); static Type* getOrCreateStructTypeWithConstraints(bool islit, std::string name, std::vector mems); static Type* getOrCreateFunctionTypeWithConstraints(bool isva, std::vector args, Type* ret); }; struct BoolType : Type { friend struct Type; virtual std::string str() override; virtual std::string encodedStr() override; virtual bool isTypeEqual(Type* other) override; virtual Type* substitutePlaceholders(const util::hash_map& subst) override; // protected constructor virtual ~BoolType() override { } BoolType(); protected: public: static BoolType* get(); }; struct VoidType : Type { friend struct Type; virtual std::string str() override; virtual std::string encodedStr() override; virtual bool isTypeEqual(Type* other) override; virtual Type* substitutePlaceholders(const util::hash_map& subst) override; // protected constructor virtual ~VoidType() override { } VoidType(); protected: public: static VoidType* get(); }; struct NullType : Type { friend struct Type; virtual std::string str() override; virtual std::string encodedStr() override; virtual bool isTypeEqual(Type* other) override; virtual Type* substitutePlaceholders(const util::hash_map& subst) override; // protected constructor virtual ~NullType() override { } NullType(); protected: public: static NullType* get(); }; // special case -- the type also needs to store the number, to know things like // whether it's signed, negative, an integer, and other stuff. struct ConstantNumberType : Type { friend struct Type; bool isSigned(); bool isFloating(); size_t getMinBits(); virtual std::string str() override; virtual std::string encodedStr() override; virtual bool isTypeEqual(Type* other) override; virtual Type* substitutePlaceholders(const util::hash_map& subst) override; static ConstantNumberType* get(bool neg, bool flt, size_t bits); virtual ~ConstantNumberType() override { } protected: ConstantNumberType(bool neg, bool floating, size_t bits); bool _floating = false; bool _signed = false; size_t _bits = 0; }; struct PolyPlaceholderType : Type { friend struct Type; virtual std::string str() override; virtual std::string encodedStr() override; virtual bool isTypeEqual(Type* other) override; virtual Type* substitutePlaceholders(const util::hash_map& subst) override; std::string getName(); int getGroup(); // session allows placeholders to share a name while being unrelated. static PolyPlaceholderType* get(const std::string& name, int session); virtual ~PolyPlaceholderType() override { } protected: PolyPlaceholderType(const std::string& n, int ses); std::string name; int group = 0; }; struct PrimitiveType : Type { friend struct Type; // methods bool isSigned(); size_t getIntegerBitWidth(); size_t getFloatingPointBitWidth(); PrimitiveType* getOppositeSignedType(); virtual std::string str() override; virtual std::string encodedStr() override; virtual bool isTypeEqual(Type* other) override; virtual Type* substitutePlaceholders(const util::hash_map& subst) override; enum class Kind { Invalid, Integer, Floating, }; // protected constructor virtual ~PrimitiveType() override { } protected: PrimitiveType(size_t bits, bool issigned, Kind _kind); // fields (protected) bool isTypeSigned = 0; size_t bitWidth = 0; Kind primKind = Kind::Invalid; static PrimitiveType* getIntWithBitWidthAndSignage(size_t bits, bool issigned); static PrimitiveType* getFloatWithBitWidth(size_t bits); public: static PrimitiveType* getIntN(size_t bits); static PrimitiveType* getUintN(size_t bits); static PrimitiveType* getInt8(); static PrimitiveType* getInt16(); static PrimitiveType* getInt32(); static PrimitiveType* getInt64(); static PrimitiveType* getInt128(); static PrimitiveType* getUint8(); static PrimitiveType* getUint16(); static PrimitiveType* getUint32(); static PrimitiveType* getUint64(); static PrimitiveType* getUint128(); static PrimitiveType* getFloat32(); static PrimitiveType* getFloat64(); static PrimitiveType* getFloat128(); }; struct PointerType : Type { friend struct Type; virtual bool isTypeEqual(Type* other) override; PointerType* getMutable(); PointerType* getImmutable(); bool isMutable(); virtual std::string str() override; virtual std::string encodedStr() override; virtual Type* substitutePlaceholders(const util::hash_map& subst) override; // protected constructor virtual ~PointerType() override { } protected: PointerType(Type* base, bool mut); Type* baseType = 0; bool isPtrMutable = false; // static funcs public: static PointerType* getInt8Ptr(); static PointerType* getInt16Ptr(); static PointerType* getInt32Ptr(); static PointerType* getInt64Ptr(); static PointerType* getInt128Ptr(); static PointerType* getUint8Ptr(); static PointerType* getUint16Ptr(); static PointerType* getUint32Ptr(); static PointerType* getUint64Ptr(); static PointerType* getUint128Ptr(); }; struct TupleType : Type { friend struct Type; // methods size_t getElementCount(); Type* getElementN(size_t n); const std::vector& getElements(); virtual std::string str() override; virtual std::string encodedStr() override; virtual bool isTypeEqual(Type* other) override; virtual Type* substitutePlaceholders(const util::hash_map& subst) override; // protected constructor virtual ~TupleType() override { } protected: TupleType(const std::vector& mems); // fields (protected) std::vector members; public: static TupleType* get(const std::initializer_list& members); static TupleType* get(const std::vector& members); }; struct UnionVariantType; struct UnionType : Type { friend struct Type; virtual std::string str() override; virtual std::string encodedStr() override; virtual bool isTypeEqual(Type* other) override; virtual Type* substitutePlaceholders(const util::hash_map& subst) override; Name getTypeName(); size_t getVariantCount(); size_t getIdOfVariant(const std::string& name); const util::hash_map& getVariants(); bool hasVariant(const std::string& name); UnionVariantType* getVariant(const std::string& name); UnionVariantType* getVariant(size_t id); void setBody(const util::hash_map>& variants); virtual ~UnionType() override { } protected: UnionType(const Name& id, const util::hash_map>& variants); Name unionName; util::hash_map indexMap; util::hash_map variants; public: static UnionType* create(const Name& id, const util::hash_map>& variants); static UnionType* createWithoutBody(const Name& id); }; struct UnionVariantType : Type { friend struct Type; friend struct UnionType; // methods std::string getName() { return this->name; } size_t getVariantId() { return this->variantId; } Type* getInteriorType() { return this->interiorType; } UnionType* getParentUnion() { return this->parent; } virtual std::string str() override; virtual std::string encodedStr() override; virtual bool isTypeEqual(Type* other) override; virtual Type* substitutePlaceholders(const util::hash_map& subst) override; // protected constructor virtual ~UnionVariantType() override { } protected: UnionVariantType(UnionType* parent, size_t id, const std::string& name, Type* actual); // fields (protected) UnionType* parent; Type* interiorType; std::string name; size_t variantId; }; struct RawUnionType : Type { friend struct Type; Name getTypeName(); size_t getVariantCount(); bool hasVariant(const std::string& name); Type* getVariant(const std::string& name); const util::hash_map& getVariants(); void setBody(const util::hash_map& variants); virtual std::string str() override; virtual std::string encodedStr() override; virtual bool isTypeEqual(Type* other) override; virtual Type* substitutePlaceholders(const util::hash_map& subst) override; virtual ~RawUnionType() override { } protected: RawUnionType(const Name& id, const util::hash_map& variants); Name unionName; util::hash_map variants; public: static RawUnionType* create(const Name& id, const util::hash_map& variants); static RawUnionType* createWithoutBody(const Name& id); }; struct TraitType : Type { friend struct Type; // methods Name getTypeName(); size_t getMethodCount(); const std::vector>& getMethods(); void setMethods(const std::vector>& m); virtual std::string str() override; virtual std::string encodedStr() override; virtual bool isTypeEqual(Type* other) override; virtual Type* substitutePlaceholders(const util::hash_map& subst) override; // protected constructor virtual ~TraitType() override { } protected: TraitType(const Name& name, const std::vector>& meths); // fields Name traitName; std::vector> methods; // static funcs public: static TraitType* create(const Name& name); }; struct StructType : Type { friend struct Type; // methods Name getTypeName(); size_t getElementCount(); Type* getElementN(size_t n); Type* getElement(const std::string& name); bool hasElementWithName(const std::string& name); size_t getElementIndex(const std::string& name); const std::vector& getElements(); void setBody(const std::vector>& members); void addTraitImpl(TraitType* trt); bool implementsTrait(TraitType* trt); std::vector getImplementedTraits(); const util::hash_map& getIndexMap(); virtual std::string str() override; virtual std::string encodedStr() override; virtual bool isTypeEqual(Type* other) override; virtual Type* substitutePlaceholders(const util::hash_map& subst) override; // protected constructor virtual ~StructType() override { } protected: StructType(const Name& name, const std::vector>& mems, bool ispacked); // fields (protected) bool isTypePacked; Name structName; std::vector typeList; std::vector implTraits; util::hash_map indexMap; util::hash_map structMembers; // static funcs public: static StructType* createWithoutBody(const Name& name, bool isPacked = false); static StructType* create(const Name& name, const std::vector>& members, bool isPacked = false); }; struct ClassType : Type { friend struct Type; friend struct Module; // methods Name getTypeName(); size_t getElementCount(); // Type* getElementN(size_t n); Type* getElement(const std::string& name); bool hasElementWithName(const std::string& name); size_t getAbsoluteElementIndex(const std::string& name); const std::vector& getElements(); std::vector getAllElementsIncludingBase(); const std::vector& getNameList(); const util::hash_map& getElementNameMap(); const std::vector& getMethods(); std::vector getMethodsWithName(const std::string& id); Function* getMethodWithType(FunctionType* ftype); const std::vector& getInitialiserFunctions(); void setInitialiserFunctions(const std::vector& list); Function* getInlineInitialiser(); void setInlineInitialiser(Function* fn); Function* getInlineDestructor(); void setInlineDestructor(Function* fn); void setMembers(const std::vector>& members); void setMethods(const std::vector& methods); ClassType* getBaseClass(); void setBaseClass(ClassType* ty); void setDestructor(Function* f); void setCopyConstructor(Function* f); void setMoveConstructor(Function* f); Function* getDestructor(); Function* getCopyConstructor(); Function* getMoveConstructor(); void addTraitImpl(TraitType* trt); bool implementsTrait(TraitType* trt); std::vector getImplementedTraits(); bool hasParent(Type* base); void addVirtualMethod(Function* method); size_t getVirtualMethodIndex(const std::string& name, FunctionType* ft); size_t getVirtualMethodCount(); virtual std::string str() override; virtual std::string encodedStr() override; virtual bool isTypeEqual(Type* other) override; virtual Type* substitutePlaceholders(const util::hash_map& subst) override; // protected constructor virtual ~ClassType() override { } protected: ClassType(const Name& name, const std::vector>& mems, const std::vector& methods, const std::vector& inits); // fields (protected) Name className; std::vector typeList; std::vector nameList; std::vector methodList; std::vector initialiserList; std::vector implTraits; util::hash_map indexMap; util::hash_map classMembers; util::hash_map> classMethodMap; //* how it works is that we will add in the mappings from the base class, //* and for our own matching virtual methods, we'll map to the same index. size_t virtualMethodCount = 0; // util::hash_map virtualMethodMap; util::hash_map reverseVirtualMethodMap; //* note: we do it this way (where we *EXCLUDE THE SELF POINTER*), because it's just easier -- to compare, and everything. //* we really don't have a use for mapping a Function to an index, only the other way. std::map>, size_t> virtualMethodMap; ClassType* baseClass = 0; Function* inlineInitialiser = 0; Function* inlineDestructor = 0; Function* destructor = 0; Function* copyConstructor = 0; Function* moveConstructor = 0; // static funcs public: static ClassType* createWithoutBody(const Name& name); static ClassType* create(const Name& name, const std::vector>& members, const std::vector& methods, const std::vector& inits); }; struct EnumType : Type { friend struct Type; Type* getCaseType(); Name getTypeName(); ConstantValue* getNameArray(); ConstantValue* getCaseArray(); void setCaseType(Type* t); void setNameArray(ConstantValue* arr); void setCaseArray(ConstantValue* arr); virtual std::string str() override; virtual std::string encodedStr() override; virtual bool isTypeEqual(Type* other) override; virtual Type* substitutePlaceholders(const util::hash_map& subst) override; // protected constructor virtual ~EnumType() override { } protected: EnumType(const Name& name, Type* ty); Type* caseType; Name typeName; ConstantValue* runtimeNameArray = 0; ConstantValue* runtimeCasesArray = 0; // static funcs public: static EnumType* get(const Name& name, Type* caseType); }; struct ArrayType : Type { friend struct Type; // methods Type* getElementType(); size_t getArraySize(); virtual std::string str() override; virtual std::string encodedStr() override; virtual bool isTypeEqual(Type* other) override; virtual Type* substitutePlaceholders(const util::hash_map& subst) override; // protected constructor virtual ~ArrayType() override { } protected: ArrayType(Type* elmType, size_t sz); // fields (protected) size_t arraySize; Type* arrayElementType; // static funcs public: static ArrayType* get(Type* elementType, size_t num); }; struct DynamicArrayType : Type { friend struct Type; // methods Type* getElementType(); virtual std::string str() override; virtual std::string encodedStr() override; virtual bool isTypeEqual(Type* other) override; virtual Type* substitutePlaceholders(const util::hash_map& subst) override; // protected constructor virtual ~DynamicArrayType() override { } protected: DynamicArrayType(Type* elmType); // fields Type* arrayElementType; // static funcs public: static DynamicArrayType* get(Type* elementType); }; struct ArraySliceType : Type { friend struct Type; // methods Type* getElementType(); bool isMutable(); bool isVariadicType(); // simplifies the mutability checking and stuff. Type* getDataPointerType(); virtual std::string str() override; virtual std::string encodedStr() override; virtual bool isTypeEqual(Type* other) override; virtual Type* substitutePlaceholders(const util::hash_map& subst) override; // protected constructor virtual ~ArraySliceType() override { } protected: ArraySliceType(Type* elmType, bool mut); // fields bool isSliceMutable; Type* arrayElementType; bool isVariadic = false; // static funcs public: static ArraySliceType* get(Type* elementType, bool mut); static ArraySliceType* getMutable(Type* elementType); static ArraySliceType* getImmutable(Type* elementType); static ArraySliceType* getVariadic(Type* elementType); }; struct FunctionType : Type { friend struct Type; // methods const std::vector& getArgumentTypes(); size_t getArgumentCount(); Type* getArgumentN(size_t n); Type* getReturnType(); bool isCStyleVarArg(); bool isVariadicFunc(); virtual std::string str() override; virtual std::string encodedStr() override; virtual bool isTypeEqual(Type* other) override; virtual Type* substitutePlaceholders(const util::hash_map& subst) override; // protected constructor virtual ~FunctionType() override { } protected: FunctionType(const std::vector& args, Type* ret, bool iscva); // fields (protected) bool isFnCStyleVarArg; std::vector functionParams; Type* functionRetType; // static funcs public: static FunctionType* getCVariadicFunc(const std::vector& args, Type* ret); static FunctionType* getCVariadicFunc(const std::initializer_list& args, Type* ret); static FunctionType* get(const std::vector& args, Type* ret); static FunctionType* get(const std::initializer_list& args, Type* ret); }; struct RangeType : Type { friend struct Type; virtual std::string str() override; virtual std::string encodedStr() override; virtual bool isTypeEqual(Type* other) override; virtual Type* substitutePlaceholders(const util::hash_map& subst) override; // protected constructor virtual ~RangeType() override { } protected: RangeType(); public: static RangeType* get(); }; struct StringType : Type { friend struct Type; virtual std::string str() override; virtual std::string encodedStr() override; virtual bool isTypeEqual(Type* other) override; virtual Type* substitutePlaceholders(const util::hash_map& subst) override; // protected constructor virtual ~StringType() override { } protected: StringType(); public: static StringType* get(); }; struct AnyType : Type { friend struct Type; virtual std::string str() override; virtual std::string encodedStr() override; virtual bool isTypeEqual(Type* other) override; virtual Type* substitutePlaceholders(const util::hash_map& subst) override; // protected constructor virtual ~AnyType() override { } protected: AnyType(); public: static AnyType* get(); }; struct OpaqueType : Type { friend struct Type; virtual std::string str() override; virtual std::string encodedStr() override; virtual bool isTypeEqual(Type* other) override; virtual Type* substitutePlaceholders(const util::hash_map& subst) override; size_t getTypeSizeInBits() { return this->typeSizeInBits; } // protected constructor virtual ~OpaqueType() override { } protected: OpaqueType(const std::string& name, size_t sizeInBits); std::string typeName; size_t typeSizeInBits; public: static OpaqueType* get(const std::string& name, size_t sizeInBits); }; struct LocatedType { LocatedType() { } explicit LocatedType(Type* t) : type(t) { } LocatedType(Type* t, const Location& l) : type(t), loc(l) { } operator Type* () const { return this->type; } Type* operator -> () const { return this->type; } Type* type = 0; Location loc; }; struct HashTypeByStr { size_t operator() (Type* t) const { return std::hash()(t->str()); } }; struct TypesEqual { bool operator() (Type* a, Type* b) const { return a->isTypeEqual(b); } }; struct TypeCache { std::unordered_set cache; template T* getOrAddCachedType(T* type) { if(auto it = cache.find(type); it != cache.end()) { delete type; return dynamic_cast(*it); } else { cache.insert(type); return type; } } static TypeCache& get(); }; } ================================================ FILE: source/include/ir/value.h ================================================ // value.h // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include #include #include #include "type.h" #include "errors.h" #include "container.h" namespace fir { enum class LinkageType { Invalid, Internal, External, ExternalWeak, }; struct ConstantValue; struct GlobalValue; struct Instruction; struct IRBlock; struct Value { friend struct Module; friend struct Argument; friend struct IRBuilder; friend struct Instruction; friend struct ConstantValue; template friend struct util::MemoryPool; template friend struct util::FastInsertVector; // congratulations, i fucking played myself. enum class Kind { lvalue, // has identity, cannot be moved from xvalue, // has identity, can be moved from prvalue, // no identity, can be moved from }; // virtual funcs virtual Type* getType(); void setType(Type* t) { this->valueType = t; } void setKind(Kind k) { this->kind = k; } bool islvalue() { return this->kind == Kind::lvalue; } bool canmove() { return this->kind == Kind::xvalue || this->kind == Kind::prvalue; } bool isConst() { return this->isconst; } void makeConst() { this->isconst = true; } // methods void setName(const Name& idt); void setName(const std::string& s); const Name& getName(); bool hasName(); static size_t getCurrentValueId(); // protected shit size_t id; protected: virtual ~Value() { } Value(Type* type, Kind k = Kind::prvalue); // fields Name ident; Type* valueType; Kind kind; bool isconst = false; }; struct PHINode : Value { friend struct IRBuilder; void addIncoming(Value* v, IRBlock* block); std::map getValues(); protected: PHINode(Type* type); std::map incoming; }; } ================================================ FILE: source/include/lexer.h ================================================ // lexer.h // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include "defs.h" #include "container.h" namespace lexer { enum class TokenType { Invalid, Func, Class, Import, Var, Val, If, Else, Return, As, AsExclamation, Is, Switch, Case, Match, Enum, ForeignFunc, Struct, Union, Static, True, False, For, While, Do, Defer, Break, Continue, Null, Private, Public, Internal, Extension, TypeAlias, Typeof, Typeid, Sizeof, Alloc, Dealloc, Export, Namespace, Override, Trait, Virtual, Using, Mutable, Operator, LBrace, RBrace, LParen, RParen, LSquare, RSquare, LAngle, RAngle, Plus, Minus, Asterisk, Divide, SQuote, DQuote, Period, Comma, Colon, Equal, Question, Exclamation, Semicolon, Ampersand, Percent, Pipe, Dollar, LogicalOr, LogicalAnd, At, Pound, Tilde, Caret, LeftArrow, RightArrow, FatLeftArrow, FatRightArrow, EqualsTo, NotEquals, GreaterEquals, LessThanEquals, DoublePlus, DoubleMinus, PlusEq, MinusEq, MultiplyEq, DivideEq, ModEq, AmpersandEq, PipeEq, CaretEq, Ellipsis, HalfOpenEllipsis, DoubleColon, Identifier, UnicodeSymbol, Number, StringLiteral, CharacterLiteral, NewLine, Comment, EndOfFile, Attr_ATTRS_BEGIN, Attr_Raw, Attr_Packed, Attr_EntryFn, Attr_NoMangle, Attr_Operator, Attr_Platform, Attr_ATTRS_END, Directive_Run, Directive_If, }; struct Token { Location loc; TokenType type = TokenType::Invalid; std::string_view text; operator TokenType() const { return this->type; } bool operator == (const std::string& s) { return this->str() == s; } std::string str() const { return std::string(this->text); } }; using TokenList = util::FastInsertVector; lexer::TokenType getNextToken(const util::FastInsertVector& lines, size_t* line, size_t* offset, const std::string_view& whole, Location& pos, Token* out, bool crlf); } ================================================ FILE: source/include/memorypool.h ================================================ // memorypool.h // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include "container.h" namespace util { void addPool(MemoryPool_base* pool); void clearAllPools(); template T* pool(Args&&... args) { static MemoryPool _pool; addPool(&_pool); return _pool.construct(std::forward(args)...); } } ================================================ FILE: source/include/parser.h ================================================ // parser.h // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include "defs.h" #include "lexer.h" namespace ast { struct TopLevelBlock; } namespace frontend { struct ImportThing; struct FileInnards; struct CollectorState; } namespace parser { struct ParsedFile { std::string name; std::string moduleName; std::vector modulePath; ast::TopLevelBlock* root = 0; }; struct CustomOperatorDecl { Location loc; std::string symbol; int precedence = 0; enum class Kind { Invalid, Infix, Prefix, Postfix }; Kind kind = Kind::Invalid; }; std::tuple, util::hash_map, util::hash_map> parseOperators(const lexer::TokenList& tokens); // strange api size_t parseOperatorDecl(const lexer::TokenList& tokens, size_t i, int* kind, CustomOperatorDecl* out); std::vector parseImports(const std::string& filename, const lexer::TokenList& tokens); ParsedFile parseFile(const std::string& filename, const frontend::FileInnards& file, frontend::CollectorState& cs); } ================================================ FILE: source/include/parser_internal.h ================================================ // parser_internal.h // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include "defs.h" #include "errors.h" #include "ast.h" #include "lexer.h" #include "parser.h" namespace pts { struct Type; } namespace parser { struct State { State(const lexer::TokenList& tl) : tokens(tl) { } const lexer::Token& lookahead(size_t num) const { if(this->index + num < this->tokens.size()) return this->tokens[this->index + num]; else error("lookahead %d tokens > size %d", num, this->tokens.size()); } void skip(size_t num) { if(this->index + num < this->tokens.size()) this->index += num; else error("skip %d tokens > size %d", num, this->tokens.size()); } void rewind(size_t num) { if(this->index > num) this->index -= num; else error("rewind %d tokens > index %d", num, this->index); } void rewindTo(size_t ix) { if(ix >= this->tokens.size()) error("ix %d > size %d", ix, this->tokens.size()); this->index = ix; } const lexer::Token& pop() { if(this->index + 1 < this->tokens.size()) return this->tokens[this->index++]; else error("pop() on last token"); } const lexer::Token& eat() { this->skipWS(); if(this->index + 1 < this->tokens.size()) return this->tokens[this->index++]; else error("eat() on last token"); } void skipWS() { while(this->index < this->tokens.size() && (this->tokens[this->index] == lexer::TokenType::NewLine || this->tokens[this->index] == lexer::TokenType::Comment)) { this->index++; } } const lexer::Token& front() const { return this->tokens[this->index]; } const lexer::Token& frontAfterWS() { size_t ofs = 0; while(this->tokens[this->index + ofs] == lexer::TokenType::NewLine || this->tokens[this->index + ofs] == lexer::TokenType::Comment) { ofs++; } return this->tokens[this->index + ofs]; } const lexer::Token& prev() { return this->tokens[this->index - 1]; } const Location& loc() const { return this->front().loc; } const Location& ploc() const { iceAssert(this->index > 0); return this->tokens[this->index - 1].loc; } size_t remaining() const { return this->tokens.size() - this->index - 1; } size_t getIndex() const { return this->index; } void setIndex(size_t i) { iceAssert(i < tokens.size()); this->index = i; } bool frontIsWS() const { return this->front() == lexer::TokenType::Comment || this->front() == lexer::TokenType::NewLine; } bool hasTokens() const { return this->index < this->tokens.size() && this->tokens[this->index] != lexer::TokenType::EndOfFile; } const lexer::TokenList& getTokenList() { return this->tokens; } void enterFunctionBody() { this->bodyNesting.push_back(1); } void leaveFunctionBody() { iceAssert(this->bodyNesting.size() > 0 && this->bodyNesting.back() == 1); this->bodyNesting.pop_back(); } bool isInFunctionBody() { return this->bodyNesting.size() > 0 && this->bodyNesting.back() == 1; } void enterStructBody() { this->bodyNesting.push_back(2); } void leaveStructBody() { iceAssert(this->bodyNesting.size() > 0 && this->bodyNesting.back() == 2); this->bodyNesting.pop_back(); } bool isInStructBody() { return this->bodyNesting.size() > 0 && this->bodyNesting.back() == 2; } void enterSubscript() { this->bodyNesting.push_back(3); } void leaveSubscript() { iceAssert(this->bodyNesting.size() > 0 && this->bodyNesting.back() == 3); this->bodyNesting.pop_back(); } bool isInSubscript() { return this->bodyNesting.size() > 0 && this->bodyNesting.back() == 3; } void enterUsingParse() { this->bodyNesting.push_back(4); } void leaveUsingParse() { iceAssert(this->bodyNesting.size() > 0 && this->bodyNesting.back() == 4); this->bodyNesting.pop_back(); } bool isParsingUsing() { return this->bodyNesting.size() > 0 && this->bodyNesting.back() == 4; } // implicitly coerce to location, so we can // error(st, ...) operator const Location&() const { return this->loc(); } std::vector anonymousTypeDefns; std::string currentFilePath; util::hash_map binaryOps; util::hash_map prefixOps; util::hash_map postfixOps; // flags that determine whether or not 'import' and '@operator' things can still be done. bool importsStillValid = true; bool operatorsStillValid = true; bool nativeWordSizeStillValid = true; frontend::CollectorState* cState = 0; private: // 1 = inside function // 2 = inside struct // 3 = inside subscript // 4 = inside using (specifically, in `using X as Y`, we're parsing 'X') std::vector bodyNesting; size_t index = 0; const lexer::TokenList& tokens; }; // like TCResult i guess. template struct PResult { PResult(T* val) { this->state = 0; this->value = val; } explicit PResult(ErrorMsg* err, bool needsmore = false) { this->error = err; this->state = (needsmore ? 2 : 1); } private: explicit PResult(ErrorMsg* err, int stt) { this->error = err; this->state = stt; } public: PResult(const PResult& r) { this->state = r.state; if(this->state == 0) this->value = r.value; else this->error = r.error; } PResult(PResult&& r) noexcept { this->state = r.state; r.state = -1; if(this->state == 0) this->value = std::move(r.value); else this->error = std::move(r.error); } PResult& operator = (const PResult& r) { PResult tmp(r); *this = std::move(tmp); return *this; } PResult& operator = (PResult&& r) noexcept { if(&r != this) { this->state = r.state; r.state = -1; if(this->state == 0) this->value = std::move(r.value); else this->error = std::move(r.error); } return *this; } // implicit conversion operator. template >> operator A() const { if(this->state == 0) return PResult(this->value); else return PResult(this->error, this->state); } template PResult mutate(const F& fn) { if(this->state == 0) fn(this->value); return *this; } template auto map(const F& fn) const -> PResult()))>> { using U = std::decay_t()))>; if(this->state > 0) return PResult(this->error, this->state); else return PResult(fn(this->value)); } ErrorMsg* err() const { if(this->state < 1) compiler_crash("not error"); else return this->error; } T* val() const { if(this->state != 0) this->error->postAndQuit(); else return this->value; } bool isError() const { return this->state > 0; } bool hasValue() const { return this->state == 0; } bool needsMoreTokens() const { return this->state == 2; } static PResult insufficientTokensError() { return PResult(BareError::make("unexpected end of input"), /* needmore: */ true); } template static PResult copyError(const PResult& other) { // only for error. if(other.state < 1) compiler_crash("not error"); return PResult(other.err(), other.state); } template friend struct PResult; using value_t = T; private: // 0 = result, 1 = error, 2 = needsmoretokens int state; union { T* value; ErrorMsg* error; }; }; // Expected $, found '$' instead [[noreturn]] inline void expected(const Location& loc, std::string a, std::string b) { error(loc, "expected %s, found '%s' instead", a, b); } // Expected $ after $, found '$' instead [[noreturn]] inline void expectedAfter(const Location& loc, std::string a, std::string b, std::string c) { error(loc, "expected %s after %s, found '%s' instead", a, b, c); } // Unexpected $ [[noreturn]] inline void unexpected(const Location& loc, std::string a) { error(loc, "unexpected %s", a); } std::string parseStringEscapes(const Location& loc, const std::string& str); std::string parseOperatorTokens(State& st); pts::Type* parseType(State& st); ast::Expr* parseExpr(State& st); PResult parseStmt(State& st, bool allowExprs = true); ast::DeferredStmt* parseDefer(State& st); ast::Stmt* parseVariable(State& st); ast::ReturnStmt* parseReturn(State& st); ast::ImportStmt* parseImport(State& st); PResult parseFunction(State& st); PResult parseStmtWithAccessSpec(State& st); ast::ForeignFuncDefn* parseForeignFunction(State& st); ast::OperatorOverloadDefn* parseOperatorOverload(State& st); std::vector> parseCallArgumentList(State& st); ast::UsingStmt* parseUsingStmt(State& st); DecompMapping parseArrayDecomp(State& st); DecompMapping parseTupleDecomp(State& st); std::tuple parseFunctionDecl(State& st); ast::PlatformDefn* parsePlatformDefn(State& st); ast::RunDirective* parseRunDirective(State& st); ast::TraitDefn* parseTrait(State& st); ast::EnumDefn* parseEnum(State& st); ast::ClassDefn* parseClass(State& st); ast::StaticDecl* parseStaticDecl(State& st); PResult parseStruct(State& st, bool nameless); ast::UnionDefn* parseUnion(State& st, bool israw, bool nameless); ast::Expr* parseDollarExpr(State& st); ast::InitFunctionDefn* parseInitFunction(State& st); ast::InitFunctionDefn* parseDeinitFunction(State& st); ast::InitFunctionDefn* parseCopyOrMoveInitFunction(State& st, const std::string& name); ast::DeallocOp* parseDealloc(State& st); ast::SizeofOp* parseSizeof(State& st); PResult parseBracedBlock(State& st); ast::LitNumber* parseNumber(State& st); ast::LitString* parseString(State& st, bool israw); ast::LitArray* parseArray(State& st, bool israw); ast::Stmt* parseForLoop(State& st); PResult parseIfStmt(State& st); PResult parseWhileLoop(State& st); ast::TopLevelBlock* parseTopLevel(State& st, const std::string& name); ast::Stmt* parseBreak(State& st); ast::Stmt* parseContinue(State& st); ast::Expr* parseCaretOrColonScopeExpr(State& st); std::vector> parseGenericTypeList(State& st); PolyArgMapping_t parsePAMs(State& st, bool* failed); AttribSet parseAttributes(State& st); std::tuple, std::vector>, pts::Type*, bool, Location> parseFunctionLookingDecl(State& st); std::pair> parseIdentPath(const lexer::TokenList& tokens, size_t* idx); } ================================================ FILE: source/include/platform.h ================================================ // platform.h // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. // platform-specific things #pragma once #include "defs.h" #define ALLOCATE_MEMORY_FUNC "malloc" #define REALLOCATE_MEMORY_FUNC "realloc" #define FREE_MEMORY_FUNC "free" #if defined(_WIN32) #define OS_WINDOWS 1 #define OS_DARWIN 0 #define OS_UNIX 0 #elif __APPLE__ #define OS_WINDOWS 0 #define OS_DARWIN 1 #define OS_UNIX 0 #elif __unix__ #define OS_WINDOWS 0 #define OS_DARWIN 0 #define OS_UNIX 1 #else #error "invalid host os!" #endif #if defined(__x86_64__) || defined(__aarch64__) || defined(_M_X64) #define ARCH_64 1 #define ARCH_32 0 #else #define ARCH_32 1 #define ARCH_64 0 #endif #if OS_WINDOWS using filehandle_t = void*; #define CRT_FDOPEN "_fdopen" #define PLATFORM_NEWLINE "\r\n" #define PLATFORM_EXPORT_FUNCTION extern "C" __declspec(dllexport) namespace platform { std::wstring convertStringToWChar(const std::string& s); std::string convertWCharToString(const std::wstring& s); } #else #include #include namespace platform { using filehandle_t = int; } #define CRT_FDOPEN "fdopen" #define PLATFORM_NEWLINE "\n" #define PLATFORM_EXPORT_FUNCTION extern "C" __attribute__((visibility("default"))) #endif #define REFCOUNT_SIZE 8 namespace platform { extern filehandle_t InvalidFileHandle; filehandle_t openFile(const char* name, int mode, int flags); void closeFile(filehandle_t fd); size_t readFile(filehandle_t fd, void* buf, size_t count); size_t writeFile(filehandle_t fd, void* buf, size_t count); size_t getFileSize(const std::string& path); bool checkFileExists(const std::string& path); std::string_view readEntireFile(const std::string& path); void cachePreExistingFile(const std::string& path, const std::string& contents); std::string getFullPath(const std::string& partial); size_t getTerminalWidth(); void setupTerminalIfNecessary(); std::string getEnvironmentVar(const std::string& name); void pushEnvironmentVar(const std::string& name, const std::string& value); void popEnvironmentVar(const std::string& name); void printStackTrace(); void setupCrashHandlers(); namespace compiler { void performSelfDlOpen(); void performSelfDlClose(); void* getSymbol(const std::string& name); // call these as a pair void addLibrarySearchPaths(); void restoreLibrarySearchPaths(); std::vector getDefaultSharedLibraries(); std::string getExecutableName(const std::string& name); std::string getObjectFileName(const std::string& name); std::string getSharedLibraryName(const std::string& name); std::string getCompilerCommandLine(const std::vector& inputObjects, const std::string& outputFilename); #if OS_WINDOWS std::string getWindowsSDKLocation(); std::string getVSToolchainLibLocation(); std::string getVSToolchainBinLocation(); #endif } } ================================================ FILE: source/include/polymorph.h ================================================ // polymorph.h // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include "defs.h" #include "ast.h" #include "stcommon.h" #include "ir/type.h" namespace pts { struct Type; } namespace ast { struct FuncDefn; struct Parameterisable; } namespace fir { struct LocatedType; } namespace sst { struct TypecheckState; namespace poly { using ProblemSpace_t = std::vector>; struct ArgType { ArgType() { } explicit ArgType(fir::Type* t) : type(t) { } ArgType(const std::string& n, fir::Type* t, const Location& l) : name(n), type(t), loc(l) { } ArgType(const std::string& n, fir::Type* t, const Location& l, bool opt) : name(n), type(t), loc(l), optional(opt) { } ArgType(const std::string& n, fir::Type* t, const Location& l, bool opt, bool ignore) : name(n), type(t), loc(l), optional(opt), ignoreName(ignore) { } operator fir::Type* () const { return this->type; } fir::Type* operator -> () const { return this->type; } fir::LocatedType toFLT() const { return fir::LocatedType(this->type, this->loc); } std::string name; fir::Type* type = 0; Location loc; bool optional = false; bool ignoreName = false; }; struct Solution_t { Solution_t() { } explicit Solution_t(const util::hash_map& p) : solutions(p) { } bool hasSolution(const std::string& n) const ; fir::LocatedType getSolution(const std::string& n) const; void addSolution(const std::string& x, const fir::LocatedType& y); fir::Type* substitute(fir::Type* x) const; void resubstituteIntoSolutions(); void addSubstitution(fir::Type* x, fir::Type* y); bool operator == (const Solution_t& other) const; bool operator != (const Solution_t& other) const; // incorporate distance so we can use this shit for our function resolution. int distance = 0; util::hash_map solutions; util::hash_map substitutions; }; std::pair solveTypeList(const Location& callLoc, const std::vector& target, const std::vector& given, const Solution_t& partial, bool isFnCall); TCResult fullyInstantiatePolymorph(TypecheckState* fs, ast::Parameterisable* thing, const TypeParamMap_t& mappings); struct PolyRefResult { PolyRefResult(const TCResult& r, const Solution_t& s, ast::Parameterisable* t) : res(r), soln(s), thing(t) { } TCResult res; Solution_t soln; ast::Parameterisable* thing; }; std::vector findPolymorphReferences(TypecheckState* fs, const std::string& name, const std::vector& gdefs, const PolyArgMapping_t& _gmaps, fir::Type* return_infer, fir::Type* type_infer, bool isFnCall, std::vector* args); std::pair attemptToInstantiatePolymorph(TypecheckState* fs, ast::Parameterisable* thing, const std::string& name, const TypeParamMap_t& _gmaps, fir::Type* return_infer, fir::Type* type_infer, bool isFnCall, std::vector* args, bool fillplaceholders, fir::Type* problem_infer = 0); namespace internal { enum class TrfType { None, Slice, Pointer, FixedArray, DynamicArray, VariadicArray, }; struct Trf { bool operator == (const Trf& other) const { return this->type == other.type && this->data == other.data; } bool operator != (const Trf& other) const { return !(*this == other); } Trf(TrfType t, size_t d = 0) : type(t), data(d) { } TrfType type = TrfType::None; size_t data = 0; }; fir::Type* applyTransforms(fir::Type* base, const std::vector& trfs); std::pair> decomposeIntoTransforms(fir::Type* t, size_t max); std::pair> decomposeIntoTransforms(pts::Type* t); int getNextSessionId(); fir::Type* mergeNumberTypes(fir::Type* a, fir::Type* b); std::vector convertPtsTypeList(TypecheckState* fs, const ProblemSpace_t& problems, const std::vector& input, int polysession); fir::Type* convertPtsType(TypecheckState* fs, const ProblemSpace_t& problems, pts::Type* input, int polysession); std::vector unwrapFunctionParameters(TypecheckState* fs, const ProblemSpace_t& problems, const std::vector& args, int polysession); std::pair solvePolymorphWithPlaceholders(TypecheckState* fs, ast::Parameterisable* thing, const std::string& name, const TypeParamMap_t& partial); std::vector getMissingSolutions(const ProblemSpace_t& needed, const TypeParamMap_t& solution, bool allowPlaceholders); std::pair inferTypesForPolymorph(TypecheckState* fs, ast::Parameterisable* thing, const std::string& name, const ProblemSpace_t& problems, const std::vector& _input, const TypeParamMap_t& partial, fir::Type* return_infer, fir::Type*, bool isFnCall, fir::Type* problem_infer, util::hash_map* origParamOrder); } } } ================================================ FILE: source/include/precompile.h ================================================ // precompile.h // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #if !defined(PRECOMPILE_H) && !defined(DO_NOT_INCLUDE_PRECOMPILE) #define PRECOMPILE_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "zpr.h" #include "zfu.h" #endif ================================================ FILE: source/include/pts.h ================================================ // pts.h // Copyright (c) 2014 - 2016, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include "defs.h" #include "precompile.h" // Parser Type System // why in the ever-living fuck does this even exist? // type system upon type system... // it's not meant to be full-fledged (nor transferrable) // so i'm gonna use a bunch of shortcuts -- dynamic_cast everywhere, direct constructing, etc. namespace pts { struct Type; struct NamedType; struct PointerType; struct TupleType; struct ArraySliceType; struct FixedArrayType; struct DynamicArrayType; struct VariadicArrayType; struct FunctionType; struct Type { virtual ~Type() { } virtual std::string str(); NamedType* toNamedType(); TupleType* toTupleType(); PointerType* toPointerType(); FunctionType* toFunctionType(); FixedArrayType* toFixedArrayType(); ArraySliceType* toArraySliceType(); DynamicArrayType* toDynamicArrayType(); VariadicArrayType* toVariadicArrayType(); bool isNamedType(); bool isTupleType(); bool isPointerType(); bool isFunctionType(); bool isArraySliceType(); bool isFixedArrayType(); bool isDynamicArrayType(); bool isVariadicArrayType(); Location loc; protected: Type(const Location& l) : loc(l) { } }; struct InferredType : Type { virtual ~InferredType() { } InferredType(const Location& l) : Type(l) { } virtual std::string str() override { return "?"; } static InferredType* get(); }; struct NamedType : Type { virtual ~NamedType() { } virtual std::string str() override; std::string name; PolyArgMapping_t genericMapping; static NamedType* create(const Location& l, const std::string& s); static NamedType* create(const Location& l, const std::string& s, const PolyArgMapping_t& genericMapping); // private: explicit NamedType(const Location& l, const std::string& n) : Type(l), name(n) { } }; struct PointerType : Type { virtual ~PointerType() { } explicit PointerType(const Location& l, pts::Type* b, bool mut) : Type(l), base(b), isMutable(mut) { } virtual std::string str() override; pts::Type* base = 0; bool isMutable = false; }; struct TupleType : Type { virtual ~TupleType() { } explicit TupleType(const Location& l, const std::vector& ts) : Type(l), types(ts) { } virtual std::string str() override; std::vector types; }; // int[x], where x *is* a literal (eg. 4, 10, 0xF00D) struct FixedArrayType : Type { virtual ~FixedArrayType() { } explicit FixedArrayType(const Location& l, pts::Type* b, size_t s) : Type(l), base(b), size(s) { } virtual std::string str() override; pts::Type* base = 0; size_t size = 0; }; // int[x], where x is *not* a literal struct DynamicArrayType : Type { virtual ~DynamicArrayType() { } explicit DynamicArrayType(const Location& l, pts::Type* b) : Type(l), base(b) { } virtual std::string str() override; pts::Type* base = 0; }; struct VariadicArrayType : Type { virtual ~VariadicArrayType() { } explicit VariadicArrayType(const Location& l, pts::Type* b) : Type(l), base(b) { } virtual std::string str() override; pts::Type* base = 0; }; struct ArraySliceType : Type { virtual ~ArraySliceType() { } explicit ArraySliceType(const Location& l, pts::Type* b, bool m) : Type(l), base(b), mut(m) { } virtual std::string str() override; pts::Type* base = 0; bool mut = false; }; struct FunctionType : Type { virtual ~FunctionType() { } explicit FunctionType(const Location& l, const std::vector& args, pts::Type* ret) : Type(l), argTypes(args), returnType(ret) { } virtual std::string str() override; util::hash_map genericTypes; std::vector argTypes; pts::Type* returnType = 0; }; } ================================================ FILE: source/include/repl.h ================================================ // repl.h // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include "defs.h" #include namespace ztmu { struct State; } namespace repl { struct State; void start(); void setupEnvironment(); bool processLine(const std::string& line); std::optional parseAndTypecheck(const std::string& line, bool* needmore); bool runCommand(const std::string& command, ztmu::State* consoleState); // used to save/restore if we wanna do weird things. void setEnvironment(State* st); State* getEnvironment(); void saveHistory(const std::vector>& history); std::vector> loadHistory(); template static void error(const std::string& fmt, Args&&... args) { fprintf(stderr, " %s*%s %s\n", COLOUR_RED_BOLD, COLOUR_RESET, zpr::sprint(fmt, args...).c_str()); } template static void log(const std::string& fmt, Args&&... args) { printf(" %s*%s %s\n", COLOUR_GREEN_BOLD, COLOUR_RESET, zpr::sprint(fmt, args...).c_str()); } } ================================================ FILE: source/include/resolver.h ================================================ // resolver.h // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include "ast.h" #include "sst.h" #include "stcommon.h" #include namespace fir { struct LocatedType; } namespace sst { struct TypecheckState; namespace poly { struct ArgType; } namespace resolver { std::pair computeNamedOverloadDistance(const Location& fnLoc, const std::vector& target, const std::vector& _args, bool cvararg, const Location& callLoc); std::pair computeOverloadDistance(const Location& fnLoc, const std::vector& target, const std::vector& _args, bool cvararg, const Location& callLoc); TCResult resolveFunctionCall(TypecheckState* fs, const Location& callLoc, const std::string& name, std::vector* arguments, const PolyArgMapping_t& gmaps, bool traverseUp, fir::Type* inferredRetType); TCResult resolveFunctionCallFromCandidates(TypecheckState* fs, const Location& callLoc, const std::vector& cs, std::vector* arguments, const PolyArgMapping_t& gmaps, bool allowImplicitSelf); TCResult resolveConstructorCall(TypecheckState* fs, const Location& callLoc, TypeDefn* defn, const std::vector& arguments, const PolyArgMapping_t& gmaps); std::pair, ErrorMsg*> verifyStructConstructorArguments(const Location& callLoc, const std::string& name, const std::vector& fieldNames, const std::vector& arguments); TCResult resolveAndInstantiatePolymorphicUnion(TypecheckState* fs, sst::UnionVariantDefn* uvd, std::vector* arguments, fir::Type* return_infer, bool isFnCall); ErrorMsg* createErrorFromFailedCandidates(TypecheckState* fs, const Location& callLoc, const std::string& name, const std::vector& args, const std::vector>& fails); namespace misc { std::pair canonicalisePolyArguments(TypecheckState* fs, ast::Parameterisable* thing, const PolyArgMapping_t& pams); std::vector typecheckCallArguments(TypecheckState* fs, const std::vector>& args); template util::hash_map getNameIndexMap(const std::vector& params) { util::hash_map ret; for(size_t i = 0; i < params.size(); i++) { const auto& arg = params[i]; ret[arg.name] = i; } return ret; } } namespace internal { std::pair> resolveFunctionCallFromCandidates(TypecheckState* fs, const Location& callLoc, const std::vector>>& cands, const PolyArgMapping_t& gmaps, bool allowImplicitSelf, fir::Type* return_infer); } } } ================================================ FILE: source/include/sst.h ================================================ // sst.h // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include "defs.h" #include "sst_expr.h" #include "mpreal/mpreal.h" namespace fir { struct Type; struct ClassType; struct FunctionType; struct Function; struct ConstantValue; } namespace cgn { struct CodegenState; } namespace ast { struct FuncDefn; struct TypeDefn; } namespace sst { //! ACHTUNG ! //* note: this is the thing that everyone calls to check the mutability of a slice of something //* defined in typecheck/slice.cpp bool getMutabilityOfSliceOfType(fir::Type* ty); struct StateTree; struct Block; struct HasBlocks { HasBlocks() { } virtual ~HasBlocks() { } virtual std::vector getBlocks() = 0; bool elideMergeBlock = false; }; struct TypeDefn : Defn { TypeDefn(const Location& l) : Defn(l) { this->readableName = "type definition"; } ~TypeDefn() { } ast::TypeDefn* original = 0; Scope innerScope; }; struct TypeExpr : Expr { virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; //* allows us to intern this, so we don't leak memory. static TypeExpr* make(const Location& l, fir::Type* t); TypeExpr(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = ""; } ~TypeExpr() { } }; struct RawValueExpr : Expr { RawValueExpr(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = ""; } ~RawValueExpr() { } virtual CGResult _codegen(cgn::CodegenState*, fir::Type* = 0) override { return this->rawValue; } CGResult rawValue; }; struct ArgumentDefn; struct Block : Stmt { Block(const Location& l) : Stmt(l) { this->readableName = "block"; } ~Block() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; Location closingBrace; bool isSingleExpr = false; std::vector statements; std::vector deferred; std::function preBodyCode; std::function postBodyCode; }; struct IfStmt : Stmt, HasBlocks { IfStmt(const Location& l) : Stmt(l) { this->readableName = "if statement"; } ~IfStmt() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; virtual std::vector getBlocks() override; struct Case { Expr* cond = 0; Block* body = 0; std::vector inits; Case(Expr* c, Block* b, const std::vector& i) : cond(c), body(b), inits(i) { } }; std::vector cases; Block* elseCase = 0; }; struct ReturnStmt : Stmt { ReturnStmt(const Location& l) : Stmt(l) { this->readableName = "return statement"; } ~ReturnStmt() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; Expr* value = 0; fir::Type* expectedType = 0; }; struct WhileLoop : Stmt, HasBlocks { WhileLoop(const Location& l) : Stmt(l) { this->readableName = "while loop"; } ~WhileLoop() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; virtual std::vector getBlocks() override; Expr* cond = 0; Block* body = 0; bool isDoVariant = false; }; struct VarDefn; struct ForeachLoop : Stmt, HasBlocks { ForeachLoop(const Location& l) : Stmt(l) { this->readableName = "for loop"; } ~ForeachLoop() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; virtual std::vector getBlocks() override; VarDefn* indexVar = 0; DecompMapping mappings; Expr* array = 0; Block* body = 0; }; struct BreakStmt : Stmt { BreakStmt(const Location& l) : Stmt(l) { this->readableName = "break statement"; } ~BreakStmt() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; }; struct ContinueStmt : Stmt { ContinueStmt(const Location& l) : Stmt(l) { this->readableName = "continue statement"; } ~ContinueStmt() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; }; struct SizeofOp : Expr { SizeofOp(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "sizeof expression"; } ~SizeofOp() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; fir::Type* typeToSize = 0; }; struct TypeidOp : Expr { TypeidOp(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "sizeof expression"; } ~TypeidOp() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; fir::Type* typeToId = 0; }; struct FunctionDefn; struct AllocOp : Expr { AllocOp(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "alloc statement"; } ~AllocOp() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; fir::Type* elmType = 0; std::vector counts; std::vector arguments; Defn* constructor = 0; VarDefn* initBlockVar = 0; VarDefn* initBlockIdx = 0; Block* initBlock = 0; bool isMutable = false; }; struct DeallocOp : Stmt { DeallocOp(const Location& l) : Stmt(l) { this->readableName = "free statement"; } ~DeallocOp() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; Expr* expr = 0; }; struct BinaryOp : Expr { BinaryOp(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "binary expression"; } ~BinaryOp() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; Expr* left = 0; Expr* right = 0; std::string op; FunctionDefn* overloadedOpFunction = 0; }; struct UnaryOp : Expr { UnaryOp(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "unary expression"; } ~UnaryOp() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; Expr* expr = 0; std::string op; FunctionDefn* overloadedOpFunction = 0; }; struct AssignOp : Expr { AssignOp(const Location& l); ~AssignOp() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; std::string op; Expr* left = 0; Expr* right = 0; }; //* for the case where we assign to a tuple literal, to enable (a, b) = (b, a) (or really (a, b) = anything) struct TupleAssignOp : Expr { TupleAssignOp(const Location& l); ~TupleAssignOp() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; std::vector lefts; Expr* right = 0; }; struct SubscriptDollarOp : Expr { SubscriptDollarOp(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "dollar expression"; } ~SubscriptDollarOp() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; }; struct SubscriptOp : Expr { SubscriptOp(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "subscript expression"; } ~SubscriptOp() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; Expr* expr = 0; Expr* inside = 0; }; struct SliceOp : Expr { SliceOp(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "slice expression"; } ~SliceOp() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; Expr* expr = 0; Expr* begin = 0; Expr* end = 0; }; struct FunctionCall : Expr { FunctionCall(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "function call"; } ~FunctionCall() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; std::string name; Defn* target = 0; std::vector arguments; bool isImplicitMethodCall = false; }; struct ExprCall : Expr { ExprCall(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "function call"; } ~ExprCall() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; Expr* callee = 0; std::vector arguments; }; struct StructDefn; struct ClassDefn; struct StructConstructorCall : Expr { StructConstructorCall(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "struct constructor call"; } ~StructConstructorCall() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; StructDefn* target = 0; std::vector arguments; }; struct ClassConstructorCall : Expr { ClassConstructorCall(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "class constructor call"; } ~ClassConstructorCall() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; ClassDefn* classty = 0; FunctionDefn* target = 0; std::vector arguments; }; struct BaseClassConstructorCall : ClassConstructorCall { BaseClassConstructorCall(const Location& l, fir::Type* t) : ClassConstructorCall(l, t) { this->readableName = "base class constructor call"; } ~BaseClassConstructorCall() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; }; struct VarDefn; struct VarRef : Expr { VarRef(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "identifier"; } ~VarRef() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; std::string name; Defn* def = 0; bool isImplicitField = false; }; struct SelfVarRef : Expr { SelfVarRef(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "this"; } ~SelfVarRef() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; }; struct ScopeExpr : Expr { ScopeExpr(const Location& l, fir::Type* t, const Scope& scope) : Expr(l, t), scope(scope) { this->readableName = ""; } ~ScopeExpr() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; Scope scope; }; struct FieldDotOp : Expr { FieldDotOp(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "field access"; } ~FieldDotOp() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; Expr* lhs = 0; std::string rhsIdent; bool isMethodRef = false; bool isTransparentField = false; size_t indexOfTransparentField = 0; }; struct MethodDotOp : Expr { MethodDotOp(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "method call"; } ~MethodDotOp() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; Expr* lhs = 0; Expr* call = 0; }; struct TupleDotOp : Expr { TupleDotOp(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "tuple access"; } ~TupleDotOp() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; Expr* lhs = 0; size_t index = 0; }; struct BuiltinDotOp : Expr { BuiltinDotOp(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "dot operator"; } ~BuiltinDotOp() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; Expr* lhs = 0; std::string name; bool isFunctionCall = false; std::vector args; }; struct EnumDefn; struct EnumDotOp : Expr { EnumDotOp(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "enum case access"; } ~EnumDotOp() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; std::string caseName; EnumDefn* enumeration = 0; }; struct LiteralNumber : Expr { LiteralNumber(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "number literal"; } ~LiteralNumber() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; mpfr::mpreal num; }; struct LiteralString : Expr { LiteralString(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "string literal"; } ~LiteralString() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; std::string str; bool isCString = false; }; struct LiteralNull : Expr { LiteralNull(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "null literal"; } ~LiteralNull() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; }; struct LiteralBool : Expr { LiteralBool(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "boolean literal"; } ~LiteralBool() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; bool value = false; }; struct LiteralChar : Expr { LiteralChar(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "character literal"; } ~LiteralChar() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; uint32_t value = false; }; struct LiteralTuple : Expr { LiteralTuple(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "tuple literal"; } ~LiteralTuple() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; std::vector values; }; struct LiteralArray : Expr { LiteralArray(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "array literal"; } ~LiteralArray() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; std::vector values; }; struct RangeExpr : Expr { RangeExpr(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "range expression"; } ~RangeExpr() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; Expr* start = 0; Expr* end = 0; Expr* step = 0; bool halfOpen = false; }; struct SplatExpr : Expr { SplatExpr(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "splat expression"; } ~SplatExpr() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* infer = 0) override; Expr* inside = 0; }; struct NamespaceDefn : Stmt { NamespaceDefn(const Location& l) : Stmt(l) { this->readableName = "namespace"; } ~NamespaceDefn() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; std::string name; std::vector statements; }; struct VarDefn : Defn { VarDefn(const Location& l) : Defn(l) { this->readableName = "variable definition"; } ~VarDefn() { } virtual std::string getKind() override { return "variable"; } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; Expr* init = 0; bool immutable = false; FunctionDefn* definingFunction = 0; }; struct ArgumentDefn : VarDefn { ArgumentDefn(const Location& l) : VarDefn(l) { this->readableName = ""; this->immutable = true; } ~ArgumentDefn() { } virtual std::string getKind() override { return "argument"; } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; }; struct FunctionDecl : Defn { std::vector params; fir::Type* returnType = 0; fir::Type* parentTypeForMethod = 0; bool isVarArg = false; virtual std::string getKind() override { return "function"; } protected: FunctionDecl(const Location& l) : Defn(l) { this->readableName = "function declaration"; } ~FunctionDecl() { } }; struct FunctionDefn : FunctionDecl { FunctionDefn(const Location& l) : FunctionDecl(l) { this->readableName = "function definition"; } ~FunctionDefn() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; std::vector arguments; // bleh, this exists so we can go *into* the scope to inspect stuff if necessary StateTree* insideTree = 0; Block* body = 0; bool needReturnVoid = false; bool isVirtual = false; bool isOverride = false; bool isMutating = false; ast::FuncDefn* original = 0; }; struct ForeignFuncDefn : FunctionDecl { ForeignFuncDefn(const Location& l) : FunctionDecl(l) { this->readableName = "foreign function definition"; } ~ForeignFuncDefn() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; bool isIntrinsic = false; std::string realName; }; struct OperatorOverloadDefn : FunctionDefn { OperatorOverloadDefn(const Location& l) : FunctionDefn(l) { this->readableName = "operator overload definition"; } ~OperatorOverloadDefn() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; }; struct DecompDefn : Stmt { DecompDefn(const Location& l) : Stmt(l) { this->readableName = "destructuring variable definition"; } ~DecompDefn() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; Expr* init = 0; bool immutable = false; DecompMapping bindings; }; struct StructFieldDefn : VarDefn { StructFieldDefn(const Location& l) : VarDefn(l) { } ~StructFieldDefn() { } virtual std::string getKind() override { return "field"; } virtual CGResult _codegen(cgn::CodegenState*, fir::Type* = 0) override { return CGResult(0); } TypeDefn* parentType = 0; bool isTransparentField = false; }; struct ClassInitialiserDefn : FunctionDefn { ClassInitialiserDefn(const Location& l) : FunctionDefn(l) { } ~ClassInitialiserDefn() { } virtual std::string getKind() override { return "initialiser"; } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override { return this->FunctionDefn::_codegen(cs, inferred); } }; struct BareTypeDefn : TypeDefn { BareTypeDefn(const Location& l) : TypeDefn(l) { this->readableName = "type definition"; } ~BareTypeDefn() { } virtual std::string getKind() override { return "type"; } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; }; struct TraitDefn : TypeDefn { TraitDefn(const Location& l) : TypeDefn(l) { this->readableName = "trait definition"; } ~TraitDefn() { } virtual std::string getKind() override { return "trait"; } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; std::vector methods; }; struct StructDefn : TypeDefn { StructDefn(const Location& l) : TypeDefn(l) { this->readableName = "struct definition"; } ~StructDefn() { } virtual std::string getKind() override { return "struct"; } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; std::vector fields; std::vector methods; std::vector traits; }; struct ClassDefn : StructDefn { ClassDefn(const Location& l) : StructDefn(l) { this->readableName = "class definition"; } ~ClassDefn() { } virtual std::string getKind() override { return "class"; } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; ClassDefn* baseClass = 0; std::vector nestedTypes; std::vector staticFields; std::vector staticMethods; std::vector initialisers; FunctionDefn* deinitialiser = 0; FunctionDefn* copyInitialiser = 0; FunctionDefn* moveInitialiser = 0; }; struct EnumCaseDefn : Defn { EnumCaseDefn(const Location& l) : Defn(l) { this->readableName = "enum case definition"; } ~EnumCaseDefn() { } virtual std::string getKind() override { return "enum case"; } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; Expr* val = 0; size_t index = 0; EnumDefn* parentEnum = 0; fir::ConstantValue* value = 0; }; struct EnumDefn : TypeDefn { EnumDefn(const Location& l) : TypeDefn(l) { this->readableName = "enum definition"; } ~EnumDefn() { } virtual std::string getKind() override { return "enum"; } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; fir::Type* memberType = 0; util::hash_map cases; }; struct RawUnionDefn : TypeDefn { RawUnionDefn(const Location& l) : TypeDefn(l) { this->readableName = "raw union definition"; } ~RawUnionDefn() { } virtual std::string getKind() override { return "raw union"; } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; util::hash_map fields; std::vector transparentFields; }; struct UnionVariantDefn; struct UnionDefn : TypeDefn { UnionDefn(const Location& l) : TypeDefn(l) { this->readableName = "union definition"; } ~UnionDefn() { } virtual std::string getKind() override { return "union"; } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; util::hash_map variants; }; struct UnionVariantDefn : TypeDefn { UnionVariantDefn(const Location& l) : TypeDefn(l) { this->readableName = "union variant definition"; } ~UnionVariantDefn() { } virtual std::string getKind() override { return "union variant"; } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; std::string variantName; UnionDefn* parentUnion = 0; }; struct UnionVariantConstructor : Expr { UnionVariantConstructor(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "union constructor"; } ~UnionVariantConstructor() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; size_t variantId = 0; UnionDefn* parentUnion = 0; std::vector args; }; struct RunDirective : Expr { RunDirective(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "run directive"; } ~RunDirective() { } virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; // mutually exclusive! Block* block = 0; Expr* insideExpr = 0; }; } ================================================ FILE: source/include/sst_expr.h ================================================ // sst_expr.h // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include "defs.h" #include "stcommon.h" namespace cgn { struct CodegenState; } namespace sst { struct Stmt : Locatable { Stmt(const Location& l) : Locatable(l, "statement") { } virtual ~Stmt() { } virtual CGResult codegen(cgn::CodegenState* cs, fir::Type* inferred = 0); virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) = 0; AttribSet attrs; }; struct Expr : Stmt { Expr(const Location& l, fir::Type* t) : Stmt(l), type(t) { this->readableName = "expression"; } ~Expr() { } fir::Type* type = 0; }; struct Defn : Stmt { Defn(const Location& l) : Stmt(l) { this->readableName = "definition"; } ~Defn() { } virtual CGResult codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; Identifier id; fir::Type* type = 0; bool global = false; std::string bareName; VisibilityLevel visibility = VisibilityLevel::Internal; Scope enclosingScope; size_t cachedCSId = 0; bool didCodegen = false; CGResult cachedResult = CGResult(0); virtual std::string getKind() = 0; }; } ================================================ FILE: source/include/stcommon.h ================================================ // stcommon.h // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include "defs.h" namespace sst { struct VarDefn; struct StateTree; } namespace ast { struct Expr; } namespace attr { using FlagTy = uint32_t; constexpr FlagTy NONE = 0x0; constexpr FlagTy FN_ENTRYPOINT = 0x1; constexpr FlagTy NO_MANGLE = 0x2; constexpr FlagTy RAW = 0x4; constexpr FlagTy PACKED = 0x8; } struct AttribSet { using FlagTy = attr::FlagTy; struct UserAttrib { UserAttrib(const std::string& name, const std::vector& args) : name(name), args(args) { } std::string name; std::vector args; }; bool has(const std::string& uaName) { return std::find_if(this->userAttribs.begin(), this->userAttribs.end(), [uaName](const UserAttrib& ua) -> bool { return ua.name == uaName; }) != this->userAttribs.end(); } UserAttrib get(const std::string& uaName) { auto it = std::find_if(this->userAttribs.begin(), this->userAttribs.end(), [uaName](const UserAttrib& ua) -> bool { return ua.name == uaName; }); // would use optionals or something but lazy if(it != this->userAttribs.end()) return *it; else return UserAttrib("", {}); } void set(FlagTy x) { this->flags |= x; } bool has(FlagTy x) const { return (this->flags & x); } bool hasAny(FlagTy x) const { return (this->flags & x); } bool hasAll(FlagTy x) const { return (this->flags & x); } template void set(FlagTy x, Args... xs) { this->flags |= x; set(xs...); } template bool hasAny(FlagTy x, Args... xs) const { return (this->flags & x) || hasAny(xs...); } template bool hasAll(FlagTy x, Args... xs) const { return (this->flags & x) && hasAll(xs...); } void add(const UserAttrib& ua) { this->userAttribs.push_back(ua); } static AttribSet of(FlagTy flags, const std::vector& attribs = {}) { return AttribSet { .flags = flags, .userAttribs = attribs }; } FlagTy flags = attr::NONE; std::vector userAttribs; }; struct DecompMapping { Location loc; std::string name; bool ref = false; bool array = false; sst::VarDefn* createdDefn = 0; std::vector inner; // for array decompositions, this will hold the rest. std::string restName; bool restRef = false; sst::VarDefn* restDefn = 0; }; struct FnCallArgument { FnCallArgument() { } FnCallArgument(const Location& l, const std::string& n, sst::Expr* v, ast::Expr* o) : loc(l), name(n), value(v), orig(o) { } Location loc; std::string name; sst::Expr* value = 0; ast::Expr* orig = 0; bool ignoreName = false; static FnCallArgument make(const Location& l, const std::string& n, fir::Type* t, bool ignoreName = false); bool operator == (const FnCallArgument& other) const { return this->loc == other.loc && this->name == other.name && this->value == other.value && this->orig == other.orig; } }; struct FnParam { FnParam() { } FnParam(const Location& l, const std::string& n, fir::Type* t) : loc(l), name(n), type(t) { } Location loc; std::string name; fir::Type* type = 0; sst::Expr* defaultVal = 0; }; ================================================ FILE: source/include/string_consts.h ================================================ // string_consts.h // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. #pragma once // is this too many levels of nesting? namespace strs { namespace attrs { inline constexpr auto COMPILER_SUPPORT = "compiler_support"; } namespace names { namespace saa { inline constexpr auto FN_APPEND = "append"; inline constexpr auto FN_CLONE = "clone"; inline constexpr auto FIELD_LENGTH = "length"; inline constexpr auto FIELD_POINTER = "ptr"; inline constexpr auto FIELD_REFCOUNT = "refcount"; inline constexpr auto FIELD_CAPACITY = "capacity"; } namespace range { inline constexpr auto FIELD_BEGIN = "begin"; inline constexpr auto FIELD_END = "end"; inline constexpr auto FIELD_STEP = "step"; } // obviously cos enum is a keyword namespace enumeration { inline constexpr auto FIELD_VALUE = "value"; inline constexpr auto FIELD_INDEX = "index"; inline constexpr auto FIELD_NAME = "name"; } namespace string { inline constexpr auto FIELD_COUNT = "count"; } namespace array { inline constexpr auto FN_POP = "pop"; } namespace any { inline constexpr auto FIELD_TYPEID = "id"; inline constexpr auto FIELD_REFCOUNT = "refcount"; } namespace support { inline constexpr auto RAII_TRAIT_DROP = "raii_trait::drop"; inline constexpr auto RAII_TRAIT_COPY = "raii_trait::copy"; inline constexpr auto RAII_TRAIT_MOVE = "raii_trait::move"; } inline constexpr auto GLOBAL_INIT_FUNCTION = "global_init_function__"; } } ================================================ FILE: source/include/typecheck.h ================================================ // typecheck.h // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #pragma once #include "sst.h" #include "precompile.h" #include #include namespace parser { struct ParsedFile; } namespace frontend { struct CollectorState; struct ImportThing; } namespace pts { struct Type; } namespace ast { struct Stmt; struct TypeDefn; struct FuncDefn; struct Parameterisable; } namespace fir { struct ConstantNumberType; } namespace sst { namespace poly { struct Solution_t; } struct StateTree { StateTree(const std::string& nm, StateTree* p, bool anon = false) : name(nm), parent(p), isAnonymous(anon) { } std::string name; std::string moduleName; StateTree* parent = 0; // for those anonymous scopes (with numbers) that we create. // currently we only keep track of this for scope-path resolution, so we can skip them // when we do '^' -- if not we'll end up in the middle of something and the user doesn't expect // there to be scopes where there are no braces! bool isAnonymous = false; // this flag allows us to skip definitions that are generated by the compiler. every module // needs these definitions to be generated, but they should *not* be imported into other modules // like normal things. bool isCompilerGenerated = false; util::hash_map subtrees; util::hash_map> unresolvedGenericDefs; util::hash_map> definitions; std::vector exports; std::vector imports; std::vector reexports; // when importing *not* `as _`, the module goes into a new StateTree with the same name, and that new tree // is the one that imports the target module. (this is because the 'imports' list does not introduce a "new layer") // so, we must point the newly created module to the target module somehow. StateTree* proxyOf = nullptr; // this is a mapping from every StateTree in `imports` to the location of the `import` or `using` statement. // it only used for error-reporting, so it is stored out-of-line so the usage of `this->imports` is not more // cumbersome than it needs to be. std::map importMetadata; // the same thing, but for reexports (ie. public imports). std::map reexportMetadata; // what's there to explain? a simple map of operators to their functions. we use // function overload resolution to determine which one to call, and ambiguities are // handled the usual way. util::hash_map> infixOperatorOverloads; util::hash_map> prefixOperatorOverloads; util::hash_map> postfixOperatorOverloads; Scope cachedScope; const Scope& getScope(); StateTree* findSubtree(const std::string& name); StateTree* findOrCreateSubtree(const std::string& name, bool anonymous = false); std::vector getAllDefinitions(); std::vector getDefinitionsWithName(const std::string& name); std::vector getUnresolvedGenericDefnsWithName(const std::string& name); void addDefinition(const std::string& name, Defn* def, const TypeParamMap_t& gmaps = { }); }; struct DefinitionTree { DefinitionTree(StateTree* st) : base(st) { } StateTree* base = 0; NamespaceDefn* topLevel = 0; std::unordered_set thingsImported; util::hash_map typeDefnMap; util::hash_map compilerSupportDefinitions; }; struct TypecheckState { TypecheckState(StateTree* st) : dtree(new DefinitionTree(st)), stree(dtree->base), typeDefnMap(dtree->typeDefnMap) { } std::string moduleName; DefinitionTree* dtree = 0; StateTree* stree = 0; util::hash_map& typeDefnMap; std::vector bodyStack; std::vector currentFunctionStack; bool isInFunctionBody(); FunctionDefn* getCurrentFunction(); void enterFunctionBody(FunctionDefn* fn); void leaveFunctionBody(); std::vector subscriptArrayStack; Expr* getCurrentSubscriptArray(); void enterSubscript(Expr* arr); void leaveSubscript(); bool isInSubscript(); std::vector selfContextStack; fir::Type* getCurrentSelfContext(); void pushSelfContext(fir::Type* str); void popSelfContext(); bool hasSelfContext(); std::vector genericContextStack; std::vector getGenericContextStack(); void pushGenericContext(); fir::Type* findGenericMapping(const std::string& name, bool allowFail); void addGenericMapping(const std::string& name, fir::Type* ty); void removeGenericMapping(const std::string& name); void popGenericContext(); int breakableBodyNest = 0; void enterBreakableBody(); void leaveBreakableBody(); bool isInBreakableBody(); int deferBlockNest = 0; void enterDeferBlock(); void leaveDeferBlock(); bool isInDeferBlock(); std::vector locationStack; void pushLoc(const Location& l); void pushLoc(ast::Stmt* stmt); Location popLoc(); Location loc(); void pushAnonymousTree(); void pushTree(const std::string& name, bool createAnonymously = false); StateTree* popTree(); Scope scope(); std::vector teleportationStack; void teleportInto(const Scope& scope); void teleportOut(); std::vector getDefinitionsWithName(const std::string& name, StateTree* tree = 0); ErrorMsg* checkForShadowingOrConflictingDefinition(Defn* def, std::function checkConflicting, StateTree* tree = 0); fir::Type* getBinaryOpResultType(fir::Type* a, fir::Type* b, const std::string& op, sst::FunctionDefn** overloadFn = 0); fir::Type* convertParserTypeToFIR(pts::Type* pt, bool allowFailure = false); fir::Type* checkIsBuiltinConstructorCall(const std::string& name, const std::vector& arguments); bool checkAllPathsReturn(FunctionDefn* fn); std::pair, SimpleError> verifyStructConstructorArguments(const std::string& name, const std::set& fieldNames, const std::vector& params); DecompMapping typecheckDecompositions(const DecompMapping& bind, fir::Type* rhs, bool immut, bool allowref); }; fir::Type* inferCorrectTypeForLiteral(fir::ConstantNumberType* lit); bool isDuplicateOverload(const std::vector& a, const std::vector& b); int getOverloadDistance(const std::vector& a, const std::vector& b); void mergeExternalTree(const Location& importer, const char* kind, sst::StateTree* base, sst::StateTree* branch); DefinitionTree* typecheck(frontend::CollectorState* cs, const parser::ParsedFile& file, const std::vector>& imports, bool addPreludeDefinitions); } ================================================ FILE: source/include/zfu.h ================================================ // zfu.h // Copyright (c) 2020, zhiayang // Licensed under the Apache License Version 2.0. // updated 10/06/2020 // origins: // flax -- post 16/06/2020 // ikurabot -- pre 16/06/2020 #pragma once #include #include #include #include #include #include template std::vector operator + (const std::vector& vec, const T& elm) { auto copy = vec; copy.push_back(elm); return copy; } template std::vector operator + (const T& elm, const std::vector& vec) { auto copy = vec; copy.insert(copy.begin(), elm); return copy; } template std::vector operator + (const std::vector& a, const std::vector& b) { auto ret = a; ret.insert(ret.end(), b.begin(), b.end()); return ret; } template std::vector& operator += (std::vector& vec, const T& elm) { vec.push_back(elm); return vec; } template std::vector& operator += (std::vector& vec, const std::vector& xs) { vec.insert(vec.end(), xs.begin(), xs.end()); return vec; } namespace zfu { template bool match(const T&) { return true; } template bool match(const T& first, const U& second) { return (first == second); } template bool match(const T& first, const U& second, const Args&... comps) { return (first == second) || match(first, comps...); } template std::vector merge(const std::vector& x, const Args&... xs) { return (x + ... + xs); } template std::vector vectorOf(const T& x) { return std::vector({ x }); } template std::vector vectorOf(const T& x, const Args&... xs) { return x + vectorOf(xs...); } template >> std::vector rangeOpen(const T& begin, const T& end, const T& step = 1) { std::vector ret; ret.reserve((end - begin + 1) / step); T x = begin; while(x != end) { ret.push_back(x); x += step; } return ret; } template >> std::vector rangeClosed(const T& begin, const T& end, const T& step = 1) { return rangeOpen(begin, end + 1, step); } template std::vector iterateWhile(const T& seed, Predicate pred, UnaryOp fn) { T x = seed; std::vector ret; while(pred(x)) { ret.push_back(x); x = fn(x); } return ret; } template U foldl(const U& i, const Container& xs, FoldOp fn) { auto ret = i; for(const auto& x : xs) ret = fn(ret, x); return ret; } template T sum(const Container& xs) { return foldl(T(), xs, [](const T& a, const T& b) -> T { return a + b; }); } template auto map(const Container& input, UnaryOp fn) -> std::vector()))> { std::vector()))> ret; ret.reserve(input.size()); for(const auto& i : input) ret.push_back(fn(i)); return ret; } template auto map(Container&& input, UnaryOp fn) -> std::vector())))> { std::vector())))> ret; ret.reserve(input.size()); for(auto& i : input) ret.push_back(fn(std::move(i))); return ret; } template auto flatmap(const Container& input, UnaryOp fn) -> std::vector()))> { std::vector()))> ret; ret.reserve(input.size()); for(const auto& i : input) { auto x = fn(i); ret.insert(ret.end(), x.begin(), x.end()); } return ret; } template void foreach(const Container& input, UnaryOp fn) { for(const auto& i : input) fn(i); } template void foreachWhile(const Container& input, UnaryOp fn) { for(const auto& i : input) if(!fn(i)) break; } template void foreachIdx(const Container& input, UnaryOp fn) { for(size_t i = 0; i < input.size(); i++) fn(input[i], i); } template auto mapIdx(const Container& input, UnaryOp fn) -> std::vector(), static_cast(0)))> { std::vector(), static_cast(0)))> ret; ret.reserve(input.size()); for(size_t i = 0; i < input.size(); i++) ret.push_back(fn(input[i], i)); return ret; } template auto filterMap(const Container& input, Predicate cond, UnaryOp fn) -> std::vector()))> { std::vector()))> ret; for(const auto& i : input) if(cond(i)) ret.push_back(fn(i)); return ret; } template auto mapFilter(const Container& input, UnaryOp fn, Predicate cond) -> std::vector()))> { std::vector()))> ret; for(const auto& i : input) { auto k = fn(i); if(cond(k)) ret.push_back(k); } return ret; } template Container filter(const Container& input, Predicate cond) { Container ret; for(const auto& i : input) if(cond(i)) ret.push_back(i); return ret; } template bool matchAny(const Container& input, Predicate cond) { for(const auto& x : input) if(cond(x)) return true; return false; } template bool matchNone(const Container& input, Predicate cond) { return !matchAny(input, cond); } template bool matchAll(const Container& input, Predicate cond) { for(const auto& x : input) if(!cond(x)) return false; return true; } template size_t indexOf(const Container& input, Predicate cond) { for(size_t i = 0; i < input.size(); i++) if(cond(input[i])) return i; return -1; } template bool contains(const Container& input, const U& x) { return std::find(input.begin(), input.end(), x) != input.end(); } template std::vector take(const std::vector& v, size_t num) { return std::vector(v.begin(), v.begin() + std::min(num, v.size())); } template std::vector takeWhile(const std::vector& input, Predicate cond) { std::vector ret; for(const auto& i : input) { if(cond(i)) ret.push_back(i); else break; } return ret; } template std::vector drop(const std::vector& v, size_t num) { return std::vector(v.begin() + std::min(num, v.size()), v.end()); } template std::vector dropWhile(const std::vector& input, Predicate cond) { bool flag = false; std::vector ret; for(const auto& i : input) { if(!flag && cond(i)) continue; else flag = true; ret.push_back(i); } return ret; } template ())> std::map> groupBy(const std::vector& xs, GroupFn gfn) { std::map> groups; for(const T& x : xs) groups[gfn(x)].push_back(x); return groups; } // special case for one to many. so cartesian(1, { 1, 2, 3, 4 }) gives (1, 1), (1, 2), (1, 3), ... template std::vector> cartesian(const T& a, const std::vector& xs) { return map(xs, [&a](const U& x) -> auto { return std::make_pair(a, x); }); } // special case for two vectors, because tuples are a major pain in the ass. pairs >>> tuples. template std::vector> cartesian(const std::vector& a, const std::vector& b) { std::vector> ret; for(size_t i = 0; i < a.size(); i++) for(size_t k = 0; k < b.size(); k++) ret.push_back({ a[i], b[k] }); return ret; } template inline void cross_imp(F f) { f(); } template inline void cross_imp(F f, const std::vector& h, const std::vector&... t) { for(const H& hs : h) cross_imp([&](const Ts&... ts) { f(hs, ts...); }, t...); } template std::vector> cartesian(const std::vector&... in) { std::vector> res; cross_imp([&](Ts const&... ts) { res.emplace_back(ts...); }, in...); return res; } template std::vector> _permutations(const std::vector& xs, size_t r) { if(r == 0) return { }; auto fact = [](size_t x) -> size_t { size_t ret = 1; while(x > 1) ret *= x, x -= 1; return ret; }; std::vector> ret; if(permute_inside) ret.reserve(fact(xs.size()) / fact(xs.size() - r)); else ret.reserve(fact(xs.size()) / (fact(r) * fact(xs.size() - r))); std::function)> recurse; recurse = [&recurse, &xs, &ret](size_t R, size_t r, size_t i, std::vector cur) { if(r == R) { if(permute_inside) { do { ret.push_back(cur); } while(std::next_permutation(cur.begin(), cur.end())); } else { std::sort(cur.begin(), cur.end()); ret.push_back(cur); } } else { for(size_t k = i; k < xs.size(); k++) { cur.push_back(xs[k]); recurse(R, r + 1, k + 1, cur); cur.pop_back(); } } }; recurse(r, 0, 0, { }); return ret; } template std::vector> powerset(const std::vector& xs) { std::vector> ret; // well... if there's more than 64 elements then gg ret.reserve(2 << xs.size()); for(size_t i = 0; i < xs.size(); i++) { auto x = _permutations(xs, i); ret.insert(ret.end(), x.begin(), x.end()); } return ret; } template std::vector> combinations(const std::vector& xs, size_t r) { return _permutations(xs, r); } template std::vector> permutations(const std::vector& xs, size_t r) { return _permutations(xs, r); } template std::vector> permutations(const std::vector& xs) { return _permutations(xs, xs.size()); } template std::vector> zip(const std::vector& a, const std::vector& b) { std::vector> ret; for(size_t i = 0; i < std::min(a.size(), b.size()); i++) ret.push_back({ a[i], b[i] }); return ret; } static inline std::string join(const std::vector& list, const std::string& sep) { if(list.empty()) return ""; else if(list.size() == 1) return list[0]; std::string ret; for(size_t i = 0; i < list.size() - 1; i++) ret += list[i] + sep; return ret + list.back(); } static inline std::string serialiseScope(const std::vector& scope) { if(scope.empty()) return ""; std::string ret = scope[0]; for(size_t i = 1; i < scope.size(); i++) ret += "::" + scope[i]; return ret; } static inline std::string plural(const std::string& thing, size_t count) { return thing + (count == 1 ? "" : "s"); } template std::string listToString(const Container& list, UnaryOp fn, bool braces = true, const std::string& sep = ", ") { std::string ret; for(size_t i = 0; i < list.size(); i++) { ret += fn(list[i]); if(i != list.size() - 1) ret += sep; } return braces ? ("[ " + ret + " ]") : ret; } template std::vector> pairs(const std::unordered_map& map) { auto ret = std::vector>(map.begin(), map.end()); return ret; } template std::vector> pairs(const std::map& map) { auto ret = std::vector>(map.begin(), map.end()); return ret; } struct identity { template T&& operator() (T&& x) { return std::forward(x); } }; struct tostring { template std::string operator() (const T& x) { return std::to_string(x); } }; struct pair_first { template T operator() (const std::pair& x) { return x.first; } }; struct pair_second { template U operator() (const std::pair& x) { return x.second; } }; template struct equals_to { equals_to(const T& x) : value(x) { } bool operator() (const T& x) { return x == this->value; } private: const T& value; }; } ================================================ FILE: source/include/zpr.h ================================================ // zpr.h // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. // updated 12/07/2020 // origins: // flax -- 12/07/2020 // ikurabot -- 10/06/2020 #pragma once #include #include #include #include #include #include #ifndef ENABLE_FIELD_SIZES #define ENABLE_FIELD_SIZES 1 #endif #ifndef HEX_0X_RESPECTS_UPPERCASE #define HEX_0X_RESPECTS_UPPERCASE 1 #endif namespace zpr { struct format_args { bool zero_pad = false; bool alternate = false; bool prepend_plus_if_positive = false; bool prepend_blank_if_positive = false; char specifier = 0; int64_t width = 0; int64_t length = 0; int64_t precision = -1; constexpr static int LENGTH_DEFAULT = 0; constexpr static int LENGTH_SHORT_SHORT = 1; constexpr static int LENGTH_SHORT = 2; constexpr static int LENGTH_LONG = 3; constexpr static int LENGTH_LONG_LONG = 4; constexpr static int LENGTH_LONG_DOUBLE = 5; constexpr static int LENGTH_INTMAX_T = 6; constexpr static int LENGTH_SIZE_T = 7; constexpr static int LENGTH_PTRDIFF_T = 8; }; template struct print_formatter { template struct has_formatter { static constexpr bool value = false; }; // when printing, we use print_formatter().print(...). if there is no specialisation // for print_formatter, then we will instantiate this base class -- which causes the nice // static_assert message. note that we must use some predicate that depends on T, so that the // compiler can only know the value when it tries to instantiate. using static_assert(false) // will always fail to compile. // we make a inner type has_formatter which is more descriptive, and since we only make this // error when we try to instantiate the base, any specialisations don't even need to care! static_assert(true || has_formatter::value, "no formatter defined for type!"); }; namespace _internal { inline format_args parseFormatArgs(const char* fmt, const char** end, bool* need_width, bool* need_prec) { auto ret = format_args(); if(fmt[0] != '%') return ret; fmt++; bool negative_width = false; while(true) { switch(*fmt++) { case '0': ret.zero_pad = true; continue; case '#': ret.alternate = true; continue; case '-': negative_width = true; continue; case '+': ret.prepend_plus_if_positive = true; continue; case ' ': ret.prepend_blank_if_positive = true; continue; default: fmt--; break; } break; } if(*fmt == '*' && (fmt++, true)) { // note: if you use *, then the negative width is ignored! *need_width = true; } else { while((*fmt >= '0') && (*fmt <= '9')) ret.width = 10 * ret.width + (*fmt++ - '0'); if(negative_width) ret.width *= -1; } if(*fmt == '.' && (fmt++, true)) { if(*fmt == '*' && (fmt++, true)) { // int int_precision = va_arg(parameters, int); // ret.precision = 0 <= int_precision ? (size_t) int_precision : 0; *need_prec = true; } else if(*fmt == '-' && (fmt++, true)) { while(('0' <= *fmt) && (*fmt <= '9')) fmt++; } else { ret.precision = 0; while((*fmt >= '0') && (*fmt <= '9')) ret.precision = 10 * ret.precision + (*fmt++ - '0'); } } #if ENABLE_FIELD_SIZES if(fmt[0] == 'h') { if(fmt[1] == 'h') fmt += 2, ret.length = format_args::LENGTH_SHORT_SHORT; else fmt += 1, ret.length = format_args::LENGTH_SHORT; } else if(fmt[0] == 'l') { if(fmt[1] == 'l') fmt += 2, ret.length = format_args::LENGTH_LONG_LONG; else fmt += 1, ret.length = format_args::LENGTH_LONG; } else if(fmt[0] == 'L') fmt += 1, ret.length = format_args::LENGTH_LONG_DOUBLE; else if(fmt[0] == 't') fmt += 1, ret.length = format_args::LENGTH_PTRDIFF_T; else if(fmt[0] == 'j') fmt += 1, ret.length = format_args::LENGTH_INTMAX_T; else if(fmt[0] == 'z') fmt += 1, ret.length = format_args::LENGTH_SIZE_T; #endif ret.specifier = fmt[0]; fmt++; *end = fmt; return ret; } inline std::string skip(const char* fmt, const char** end) { std::string ret; top: while(*fmt && *fmt != '%') ret += *fmt++; if(*fmt && fmt[1] == '%') { ret += "%"; fmt += 2; goto top; } *end = fmt; return ret; } inline std::string sprint(const char* &fmt) { if(!fmt || !*fmt) return ""; auto tmp = skip(fmt, &fmt); return tmp + sprint(fmt); } // we need to forward declare this. template std::string sprint(const char* fmt, Args&&... xs); // we need bogus ones that don't take the arguments. if we get error handling, these will throw errors. template std::string _consume_both_sprint(const format_args&, const char* fmt, Args&&... xs) { return std::string("") .append(sprint(fmt, xs...)); } template std::string _consume_prec_sprint(const format_args&, const char* fmt, Args&&... xs) { return std::string("") .append(sprint(fmt, xs...)); } template std::string _consume_width_sprint(const format_args&, const char* fmt, Args&&... xs) { return std::string("") .append(sprint(fmt, xs...)); } // we need separate versions of these functions that only enable if the argument is // a pointer, THEN check if the specifier is 'p', THEN do the void* thing. template constexpr bool _stupid_type_tester(decltype(!std::is_pointer_v> || &print_formatter>::print)*) { return true; } template constexpr bool _stupid_type_tester(...) { return false; } template (0)>> std::string _consume_neither_sprint(const format_args& args, const char* fmt, T&& x, Args&&... xs) { return print_formatter>().print(x, args).append(sprint(fmt, xs...)); } template (0)>, typename F = void*> std::string _consume_neither_sprint(const format_args& args, const char* fmt, T&& x, Args&&... xs) { return print_formatter().print(x, args).append(sprint(fmt, xs...)); } template > && _stupid_type_tester(0)> > std::string _consume_width_sprint(format_args args, const char* fmt, W&& width, T&& x, Args&&... xs) { args.width = width; return print_formatter>().print(x, args).append(sprint(fmt, xs...)); } template > && !_stupid_type_tester(0)>, typename F = void* > std::string _consume_width_sprint(format_args args, const char* fmt, W&& width, T&& x, Args&&... xs) { args.width = width; return print_formatter().print(x, args).append(sprint(fmt, xs...)); } template > && _stupid_type_tester(0)> > std::string _consume_prec_sprint(format_args args, const char* fmt, P&& prec, T&& x, Args&&... xs) { args.precision = prec; return print_formatter>().print(x, args).append(sprint(fmt, xs...)); } template > && !_stupid_type_tester(0)>, typename F = void* > std::string _consume_prec_sprint(format_args args, const char* fmt, P&& prec, T&& x, Args&&... xs) { args.precision = prec; return print_formatter().print(x, args).append(sprint(fmt, xs...)); } template > && std::is_integral_v> && _stupid_type_tester(0)> > std::string _consume_both_sprint(format_args args, const char* fmt, W&& width, P&& prec, T&& x, Args&&... xs) { args.width = width; args.precision = prec; return print_formatter>().print(x, args).append(sprint(fmt, xs...)); } template > && std::is_integral_v> && !_stupid_type_tester(0)>, typename F = void* > std::string _consume_both_sprint(format_args args, const char* fmt, W&& width, P&& prec, T&& x, Args&&... xs) { args.width = width; args.precision = prec; return print_formatter().print(x, args).append(sprint(fmt, xs...)); } template std::string sprint(const char* fmt, Args&&... xs) { bool need_prec = false; bool need_width = false; std::string ret = skip(fmt, &fmt); auto args = parseFormatArgs(fmt, &fmt, &need_width, &need_prec); // because the if happens at runtime, all these functions need to be instantiable. that's // why we make bogus ones that just return error strings when there aren't enough arguments. if(need_width && need_prec) return ret.append(_consume_both_sprint(args, fmt, xs...)); else if(need_prec) return ret.append(_consume_prec_sprint(args, fmt, xs...)); else if(need_width) return ret.append(_consume_width_sprint(args, fmt, xs...)); else return ret.append(_consume_neither_sprint(args, fmt, xs...)); } } inline std::string sprint(const std::string& fmt) { return fmt; } inline int print(const std::string& fmt) { return printf("%s", fmt.c_str()); } inline int println(const std::string& fmt) { return printf("%s\n", fmt.c_str()); } template std::string sprint(const std::string& fmt, Args&&... xs) { return _internal::sprint(fmt.c_str(), xs...); } template int print(const std::string& fmt, Args&&... xs) { auto x = _internal::sprint(fmt.c_str(), xs...); return printf("%s", x.c_str()); } template int println(const std::string& fmt, Args&&... xs) { auto x = _internal::sprint(fmt.c_str(), xs...); return printf("%s\n", x.c_str()); } // formatters lie here template struct print_formatter>> && !std::is_same_v>> && !std::is_same_v>> && sizeof(T) <= sizeof(uint64_t) ) || (std::is_enum_v>>) >::type> { std::string print(T x, format_args args) { int base = 10; if(args.specifier == 'x' || args.specifier == 'X') base = 16; // else if(args.specifier == 'o') base = 8; // else if(args.specifier == 'b') base = 2; #if 0 // handle negative values ourselves btw, due to padding bool is_neg = false; if constexpr (!std::is_enum_v && std::is_signed_v) { is_neg = (x < 0); if(is_neg) x = -x; } #endif std::string digits; { // if we print base 2 we need 64 digits! char buf[65] = {0}; size_t digits_len = 0; auto spec = args.specifier; static const char* len_specs[] = { /* LENGTH_DEFAULT */ "", /* LENGTH_SHORT_SHORT */ "hh", /* LENGTH_SHORT */ "h", /* LENGTH_LONG */ "l", /* LENGTH_LONG_LONG */ "ll", /* LENGTH_LONG_DOUBLE */ "L", /* LENGTH_INTMAX_T */ "j", /* LENGTH_SIZE_T */ "z", /* LENGTH_PTRDIFF_T */ "t", }; auto len_spec = len_specs[args.length]; if(std::is_same_v>>) len_spec = "ll"; if(std::is_same_v>>) len_spec = "z"; if(std::is_same_v>>) len_spec = "ll"; auto fmt_str = ("%" + std::string(len_spec) + spec); digits_len = snprintf(&buf[0], 64, fmt_str.c_str(), x); // sadly, we must cheat here as well, because osx doesn't bloody have charconv (STILL)? // std::to_chars_result ret; // if constexpr (std::is_enum_v) // ret = std::to_chars(&buf[0], &buf[65], static_cast>(x), /* base: */ base); // else // ret = std::to_chars(&buf[0], &buf[65], x, /* base: */ base); // if(ret.ec == std::errc()) digits_len = (ret.ptr - &buf[0]), *ret.ptr = 0; // else return ""; if(isupper(args.specifier)) for(size_t i = 0; i < digits_len; i++) buf[i] = static_cast(toupper(buf[i])); digits = std::string(buf, digits_len); } std::string prefix; #if 0 if(is_neg) prefix += "-"; else #endif if(args.prepend_plus_if_positive) prefix += "+"; else if(args.prepend_blank_if_positive) prefix += " "; // prepend 0x or 0b or 0o for alternate. int64_t prefix_digits_length = 0; if((base == 2 || base == 8 || base == 16) && args.alternate) { prefix += "0"; #if HEX_0X_RESPECTS_UPPERCASE prefix += args.specifier; #else prefix += tolower(args.specifier); #endif prefix_digits_length += 2; } int64_t output_length_with_precision = (args.precision == -1 ? digits.size() : std::max(args.precision, static_cast(digits.size())) ); int64_t digits_length = prefix_digits_length + digits.size(); int64_t normal_length = prefix.size() + digits.size(); int64_t length_with_precision = prefix.size() + output_length_with_precision; bool use_precision = (args.precision != -1); bool use_zero_pad = args.zero_pad && 0 <= args.width && !use_precision; bool use_left_pad = !use_zero_pad && 0 <= args.width; bool use_right_pad = !use_zero_pad && args.width < 0; int64_t abs_field_width = std::abs(args.width); std::string pre_prefix; if(use_left_pad) pre_prefix = std::string(std::max(int64_t(0), abs_field_width - length_with_precision), ' '); std::string post_prefix; if(use_zero_pad) post_prefix = std::string(std::max(int64_t(0), abs_field_width - normal_length), '0'); std::string prec_string; if(use_precision) prec_string = std::string(std::max(int64_t(0), args.precision - digits_length), '0'); std::string postfix; if(use_right_pad) postfix = std::string(std::max(int64_t(0), abs_field_width - length_with_precision), ' '); return pre_prefix + prefix + post_prefix + prec_string + digits + postfix; } }; template struct print_formatter>>> >::type> { std::string print(const T& x, const format_args& args) { constexpr int default_prec = 6; char buf[81] = { 0 }; int64_t num_length = 0; // lmao. nobody except msvc stl (and only the most recent version) implements std::to_chars // for floating point types, even though it's in the c++17 standard. so we just cheat. // let printf handle the precision, but we'll handle the width and the negativity. { const char* fmt_str = 0; bool longdouble = (args.length == format_args::LENGTH_LONG_DOUBLE); switch(args.specifier) { case 'E': fmt_str = (longdouble ? "%.*LE" : "%.*E"); break; case 'e': fmt_str = (longdouble ? "%.*Le" : "%.*e"); break; case 'F': fmt_str = (longdouble ? "%.*LF" : "%.*F"); break; case 'f': fmt_str = (longdouble ? "%.*Lf" : "%.*f"); break; case 'G': fmt_str = (longdouble ? "%.*LG" : "%.*G"); break; case 'g': [[fallthrough]]; default: fmt_str = (longdouble ? "%.*Lg" : "%.*g"); break; } num_length = snprintf(&buf[0], 80, fmt_str, (args.precision == -1 ? default_prec : args.precision), fabs(x)); } auto abs_field_width = std::abs(args.width); bool use_zero_pad = args.zero_pad && args.width >= 0; bool use_left_pad = !use_zero_pad && args.width >= 0; bool use_right_pad = !use_zero_pad && args.width < 0; // account for the signs, if any. if(x < 0 || args.prepend_plus_if_positive || args.prepend_blank_if_positive) num_length += 1; std::string pre_prefix; if(use_left_pad) pre_prefix = std::string(std::max(int64_t(0), abs_field_width - num_length), ' '); std::string prefix; if(x < 0) prefix = "-"; else if(args.prepend_plus_if_positive) prefix = "+"; else if(args.prepend_blank_if_positive) prefix = " "; std::string post_prefix; if(use_zero_pad) post_prefix = std::string(std::max(int64_t(0), abs_field_width - num_length), '0'); std::string postfix; if(use_right_pad) postfix = std::string(std::max(int64_t(0), abs_field_width - num_length), ' '); return pre_prefix + prefix + post_prefix + std::string(buf) + postfix; } }; template struct print_formatter) || (std::is_same_v) || (std::is_same_v>) || (std::is_same_v>) >::type> { std::string print(const T& x, const format_args& args) { int64_t string_length = 0; int64_t abs_field_width = std::abs(args.width); if constexpr (std::is_pointer_v>>) { for(int64_t i = 0; (args.precision != -1 ? (i < args.precision && x && x[i]) : (x && x[i])); i++) string_length++; } else { if(args.precision >= 0) string_length = std::min(args.precision, static_cast(x.size())); else string_length = static_cast(x.size()); } std::string prefix; if(args.width >= 0 && string_length < abs_field_width) prefix = std::string(abs_field_width - string_length, ' '); std::string postfix; if(args.width < 0 && string_length < abs_field_width) postfix = std::string(abs_field_width - string_length, ' '); if constexpr (std::is_pointer_v>) return prefix + std::string(x, string_length) + postfix; else return prefix + std::string(x, 0, string_length) + postfix; } }; template struct print_formatter>>>) >::type> { std::string print(const T& x, const format_args& args) { // just reuse the string printer, but with a one-char-long string. // probably not so efficient, but idgaf for now. return print_formatter() .print(std::string(1, x), args); } }; template struct print_formatter>>>) >::type> { std::string print(const T& x, format_args args) { return print_formatter() .print(x ? "true" : "false", args); } }; template struct print_formatter>) >::type> { std::string print(const T& x, format_args args) { args.specifier = 'x'; return print_formatter() .print(reinterpret_cast(x), args); } }; } ================================================ FILE: source/include/ztmu.h ================================================ // ztmu.h // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. // terminal manipulation utilities #pragma once #include #include #include #include #include #include #include #include #include #include #include namespace ztmu { enum class Key { // start above 0xFF, so anything below we can just use as normal chars. ESCAPE = 0x100, ENTER, UP, DOWN, LEFT, RIGHT, HOME, END, DELETE, INSERT, PAGEUP, PAGEDOWN, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17, F18, F19, F20, F21, F22, F23, F24 }; enum class HandlerAction { CONTINUE, // do nothing, and continue reading the line. RETURN, // as if enter was pressed -- finish the line and give it back. QUIT // abandon ship -- return EOF. }; struct State { void clear(); void setupConsole(); void unsetupConsole(); std::optional read(); std::optional> readContinuation(const std::string& seed = ""); void setPrompt(const std::string& prompt); void setContPrompt(const std::string& prompt); void setWrappedPrompt(const std::string& prompt); void useUniqueHistory(bool enable); void addPreviousInputToHistory(); void loadHistory(const std::vector>& h); std::vector> getHistory(); void move_cursor_left(int n); void move_cursor_right(int n); void move_cursor_up(int n); void move_cursor_down(int n); void move_cursor_home(); void move_cursor_end(); void delete_left(int n); void delete_right(int n); // the handler will return true to continue reading, false to stop and return all input. void setKeyHandler(Key k, std::function handler); void unsetKeyHandler(Key k); std::string getCurrentLine(); void setCurrentLine(const std::string& s); void setMessageOnControlC(const std::string& msg); void enableExitOnEmptyControlC(); std::string promptString; std::string contPromptString; std::string wrappedPromptString; size_t normPL = 0; size_t contPL = 0; size_t wrapPL = 0; size_t cursor = 0; size_t byteCursor = 0; size_t lineIdx = 0; size_t wrappedLineIdx = 0; size_t cachedNWLForCurrentLine = 0; size_t termWidth = 0; size_t termHeight = 0; std::vector lines; std::map> keyHandlers; std::vector> history; std::vector savedCurrentInput; bool uniqueHistory = true; size_t historyIdx = 0; bool wasAborted = false; bool emptyCtrlCExits = false; std::string uselessControlCMsg; }; size_t getTerminalWidth(); size_t displayedTextLength(const std::string_view& str); inline std::vector prettyFormatTextBlock(const std::vector& paragraphs, const char* leftMargin, const char* rightMargin, size_t maxLines = 0); std::vector prettyFormatTextBlock(const std::string& block, const char* leftMargin, const char* rightMargin, size_t maxLines = 0); } namespace ztmu { namespace detail { struct CursorPosition { int x = -1; int y = -1; }; struct ControlSeq { ControlSeq() { } ControlSeq(char c) : lastChar(c) { } char lastChar; // only support max 8 params for now. int numParams = 0; int params[8]; }; void setup_console(); void unsetup_console(); size_t getTerminalWidth(); size_t getTerminalHeight(); size_t displayedTextLength(const std::string_view& str); bool read_line(State* st, int promptMode, std::string seed); void cursor_left(State* st, bool refresh = true); void cursor_right(State* st, bool refresh = true); void refresh_line(State* st, std::string* oldLine = 0); void cursor_up(State* st); void cursor_down(State* st); void cursor_home(State* st); void cursor_end(State* st, bool refresh = true); void delete_left(State* st); void delete_right(State* st); size_t convertCursorToByteCursor(const char* bytes, size_t cursor); std::vector pretty_print_text_block(const std::vector& paragraphs, const char* leftMargin, const char* rightMargin, size_t maxLines); // close out the scope here -- we don't want to #include headers in a namespace. } } #if ZTMU_CREATE_IMPL // comes as a pair yo #include "zpr.h" #ifndef _WIN32 #include #include #include #include namespace ztmu { namespace detail { static struct termios original_termios; static inline void platform_write(const char* s, size_t len) { write(STDOUT_FILENO, s, len); } static inline int platform_read_one(char* c) { return read(STDIN_FILENO, c, 1); } static inline int platform_read(char* c, size_t len) { return read(STDIN_FILENO, c, len); } static bool isInRawMode = false; static bool didRegisterAtexit = false; static inline void leaveRawMode() { if(isInRawMode && tcsetattr(STDIN_FILENO, TCSAFLUSH, &original_termios) != -1) isInRawMode = false; // disable bracketed paste: auto tmp = std::string_view("\x1b[?2004l"); platform_write(tmp.data(), tmp.size()); } static inline void enterRawMode() { if(!isatty(STDIN_FILENO)) return; if(!didRegisterAtexit) { atexit([]() { leaveRawMode(); }); didRegisterAtexit = true; } if(tcgetattr(STDIN_FILENO, &original_termios) == -1) return; // copy the original termios raw = original_termios; // input modes: no break, no CR to NL, no parity check, no strip char, // no start/stop output control. raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); // output modes - disable post processing raw.c_oflag &= ~(OPOST); // control modes - set 8 bit chars raw.c_cflag |= (CS8); // local modes - echoing off, canonical off, no extended functions, // no signal chars (^Z,^C) raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); // control chars - set return condition: min number of bytes and timer. // We want read to return every single byte, without timeout. raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* put terminal in raw mode after flushing */ if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) < 0) return; // enable bracketed paste: auto tmp = std::string_view("\x1b[?2004h"); platform_write(tmp.data(), tmp.size()); isInRawMode = true; } inline void setup_console() { // on unix, we don't really need to do anything "globally". } inline void unsetup_console() { } static struct sigaction old_sigact; static State* currentStateForSignal = 0; static inline bool setup_sigwinch() { // time for some signalling! struct sigaction new_sa; // i would use designated initialisers, but some compilers refuse to cooperate. new_sa.sa_flags = SA_RESTART; // this is important, if not read() will return EINTR (interrupted by signal) new_sa.sa_handler = [](int sig) { if(currentStateForSignal) { currentStateForSignal->termWidth = getTerminalWidth(); currentStateForSignal->termHeight = getTerminalHeight(); } }; if(sigaction(SIGWINCH, &new_sa, &old_sigact) == 0) return true; return false; } static inline void restore_sigwinch() { sigaction(SIGWINCH, &old_sigact, nullptr); } #else // mfw #define WIN32_LEAN_AND_MEAN 1 #ifndef NOMINMAX #define NOMINMAX #endif #include #include #include namespace ztmu { namespace detail { static constexpr int STDOUT_FILENO = 1; static constexpr int STDIN_FILENO = 0; static inline void platform_write(const char* s, size_t len) { DWORD written = 0; WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), s, static_cast(len), &written, NULL); } static inline int platform_read_one(char* c) { // return _read(STDIN_FILENO, c, 1); DWORD didRead = 0; ReadConsole(GetStdHandle(STD_INPUT_HANDLE), c, 1, &didRead, NULL); return didRead; } static inline int platform_read(char* c, size_t len) { DWORD didRead = 0; ReadConsole(GetStdHandle(STD_INPUT_HANDLE), c, static_cast(len), &didRead, NULL); return didRead; } static DWORD old_stdin_mode = 0; static DWORD old_stdout_mode = 0; static bool isInRawMode = false; static bool didRegisterAtexit = false; static inline void leaveRawMode() { if(!isInRawMode) return; auto stdin_handle = GetStdHandle(STD_INPUT_HANDLE); auto stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleMode(stdin_handle, old_stdin_mode); SetConsoleMode(stdout_handle, old_stdout_mode); isInRawMode = false; } static inline void enterRawMode() { if(!_isatty(STDIN_FILENO)) return; isInRawMode = true; auto stdin_handle = GetStdHandle(STD_INPUT_HANDLE); auto stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); GetConsoleMode(stdin_handle, &old_stdin_mode); GetConsoleMode(stdout_handle, &old_stdout_mode); { // this is pretty much the only flag we want. DWORD stdin_mode = ENABLE_EXTENDED_FLAGS | ENABLE_VIRTUAL_TERMINAL_INPUT; SetConsoleMode(stdin_handle, stdin_mode); // then stdout: DWORD stdout_mode = ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN; SetConsoleMode(stdout_handle, stdout_mode); } if(!didRegisterAtexit) { atexit([]() { leaveRawMode(); }); didRegisterAtexit = true; } } static UINT old_input_cp; static UINT old_output_cp; inline void setup_console() { old_input_cp = GetConsoleCP(); old_output_cp = GetConsoleOutputCP(); SetConsoleCP(CP_UTF8); SetConsoleOutputCP(CP_UTF8); } inline void unsetup_console() { SetConsoleCP(old_input_cp); SetConsoleOutputCP(old_output_cp); } static State* currentStateForSignal = 0; static inline bool setup_sigwinch() { // on windows we can't really do anything. knowing about window size changes requires using // ReadConsoleInput to poll for events, which we obviously can't do here, or use another // thread, which i'm loathe to do. so for now, suck it up, windows users. return false; } static inline void restore_sigwinch() { } #endif #if 0 template void ztmu_dbg(const char* fmt, Args&&... args) { if(!isatty(STDERR_FILENO)) fprintf(stderr, "%s", zpr::sprint(fmt, args...).c_str()); } #else template void ztmu_dbg(const char* fmt, Args&&... args) { } #endif static constexpr const char ESC = '\x1b'; static constexpr const char* CSI = "\x1b["; static inline void platform_write(const std::string_view& sv) { platform_write(sv.data(), sv.size()); } static inline std::string moveCursorUp(size_t n); static inline std::string moveCursorDown(size_t n); static inline std::string moveCursorLeft(size_t n); static inline std::string moveCursorRight(size_t n); static inline std::string moveCursorUp(size_t n) { if(n == 0) return ""; else return zpr::sprint("%s%dA", CSI, n); } static inline std::string moveCursorDown(size_t n) { if(n == 0) return ""; else return zpr::sprint("%s%dB", CSI, n); } static inline std::string moveCursorLeft(size_t n) { if(n == 0) return ""; else return zpr::sprint("%s%dD", CSI, n); } static inline std::string moveCursorRight(size_t n) { if(n == 0) return ""; else return zpr::sprint("%s%dC", CSI, n); } static CursorPosition getCursorPosition() { platform_write(zpr::sprint("%s6n", CSI)); // ok, time to read it back. format is CSI [ rows ; cols R char buf[33] { 0 }; for(size_t i = 0; i < 32; i++) { if(platform_read_one(buf + i) != 1) break; if(buf[i] == 'R') break; } // give up. if(buf[0] != ESC || buf[1] != '[') return CursorPosition(); CursorPosition ret; int gotted = sscanf(&buf[2], "%d;%d", &ret.y, &ret.x); if(gotted != 2) return CursorPosition(); return ret; } // static std::string setCursorPosition(const CursorPosition& pos) // { // if(pos.x <= 0 || pos.y <= 0) // return ""; // return zpr::sprint("%s%d;%dH", CSI, pos.y, pos.x); // } static size_t parseEscapeSequence(const std::string_view& str) { if(str.size() < 2 || str[0] != ESC) return 0; auto read_digits = [](const std::string_view& s, int* out) -> size_t { int ret = 0; size_t cons = 0; for(char c : s) { if(!isdigit(c)) break; cons++; ret = (10 * ret) + (c - '0'); } *out = ret; return cons; }; if(str[1] == ESC) { return 2; } else if(str[1] == 'N' || str[1] == 'O' || str[1] == 'c') { return 2; } else if(str[1] == 'P' || str[1] == ']' || str[1] == 'X' || str[1] == '^' || str[1] == '_') { // read till the terminator (ESC\). size_t cons = 2; while(cons + 1 < str.size() && (str[cons] != ESC || str[cons + 1] != '\\')) cons++; return cons; } else if(str[1] == '[') { // parse the params. ControlSeq csi; size_t cons = 2; while(csi.numParams < 8) { int n = 0; size_t rd = read_digits(str.substr(cons), &n); if(rd > 0) { csi.params[csi.numParams++] = n; cons += rd; if(cons < str.size() && str[cons] == ';') { cons++; continue; } else { break; } } else { break; } } csi.lastChar = str[cons++]; return cons; } else { return 0; } } inline size_t displayedTextLength(const std::string_view& str) { auto utf8_len = [](const char* begin, const char* end) -> size_t { size_t len = 0; while(*begin && begin != end) { if((*begin & 0xC0) != 0x80) len += 1; begin++; } return len; }; auto len = utf8_len(str.data(), str.data() + str.size()); { size_t cons = 0; std::string_view sv = str; size_t i = 0; while(i < sv.size()) { if(sv[i] == ESC) { size_t k = parseEscapeSequence(sv.substr(i)); i += k; cons += k; } else { i++; } } return len - cons; } } inline size_t getTerminalWidth() { #ifdef _WIN32 CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); return csbi.srWindow.Right - csbi.srWindow.Left + 1; #else #ifdef _MSC_VER #else #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" #endif struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); return w.ws_col; #ifdef _MSC_VER #else #pragma GCC diagnostic pop #endif #endif } inline size_t getTerminalHeight() { #ifdef _WIN32 CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); return csbi.srWindow.Bottom - csbi.srWindow.Top + 1; #else #ifdef _MSC_VER #else #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" #endif struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); return w.ws_row; #ifdef _MSC_VER #else #pragma GCC diagnostic pop #endif #endif } static std::string& getCurLine(State* st) { return st->lines[st->lineIdx]; } static size_t findBeginningOfUTF8CP(const uint8_t* bytes, size_t i) { if(bytes[i] <= 0x7F) return i; while(i > 0 && (bytes[i] & 0xC0) == 0x80) i -= 1; return i; } static size_t findEndOfUTF8CP(const uint8_t* bytes, size_t i) { if(bytes[i] <= 0x7F) return i; if((bytes[i] & 0xE0) == 0xC0) return i + 1; else if((bytes[i] & 0xF0) == 0xE0) return i + 2; else if((bytes[i] & 0xF8) == 0xF0) return i + 3; return i; } inline size_t convertCursorToByteCursor(const char* bytes, size_t cursor) { size_t bc = 0; for(size_t i = 0; i < cursor; i++) bc = 1 + findEndOfUTF8CP(reinterpret_cast(bytes), bc); return bc; } static std::pair calculate_left_codepoints(size_t n, const std::string_view& sv, size_t cursor, size_t byteCursor) { for(size_t i = 0; i < n; i++) { if(cursor > 0) { auto x = byteCursor - 1; auto l = findBeginningOfUTF8CP(reinterpret_cast(sv.data()), x); byteCursor -= (x - l + 1); cursor -= 1; } } return { cursor, byteCursor }; } // static std::pair calculate_right_codepoints(int n, const std::string_view& sv, size_t cursor, size_t byteCursor) // { // for(int i = 0; i < n; i++) // { // if(byteCursor < sv.size()) // { // auto x = byteCursor; // auto l = findEndOfUTF8CP(reinterpret_cast(sv.data()), x); // byteCursor += (l - x + 1); // cursor += 1; // } // } // return { cursor, byteCursor }; // } static size_t get_cursor_line_offset(size_t termWidth, size_t num, size_t firstPromptLen, size_t subsequentPromptLen, bool* didWrap = 0) { size_t hcursor = firstPromptLen; size_t x = num; while(true) { auto left = termWidth - hcursor; auto todo = std::min(left, x); x -= todo; if(x == 0) { hcursor += todo; if(hcursor == termWidth) { hcursor = subsequentPromptLen; if(didWrap) *didWrap = true; } break; } hcursor = subsequentPromptLen; } return hcursor; } static size_t calculate_wli(State* st, size_t len) { size_t done = 0; size_t remaining = len; size_t lc = 1; size_t wli = 0; while(true) { auto left = st->termWidth - (lc == 1 ? (st->lineIdx == 0 ? st->normPL : st->contPL) : st->wrapPL); auto todo = std::min(left, remaining); if(remaining == left) wli++; remaining -= todo; done += todo; if(remaining == 0) break; // if your cursor is beyond this point, then you are on the next line. if(st->cursor >= done + 1) { wli++; lc++; } } return wli; } static size_t calculate_nwl(State* st, size_t lineIdx, size_t len) { auto width = st->termWidth; size_t lines = 1; while(len > 0) { auto left = width - (lines == 1 ? (lineIdx == 0 ? st->normPL : st->contPL) : st->wrapPL); if(left == len) lines += 1; len -= std::min(left, len); if(len == 0) break; lines += 1; } return lines; } // returns (linesBelowCursor, finalHcursor) static std::pair _refresh_line(State* st, size_t lineIdx, bool skip_cursor, const std::string& oldLine, bool defer_flush, std::string* commandBuffer) { std::string commands; auto qcmd = [&commands](const std::string_view& c) { commands += c; }; auto flushcmd = [&commands]() { platform_write(commands); commands.clear(); }; auto getPromptForLine = [&](size_t wli) -> std::pair { if(lineIdx == 0) { if(wli == 0) return { st->promptString, st->normPL }; else return { st->wrappedPromptString, st->wrapPL }; } else { if(wli == 0) return { st->contPromptString, st->contPL }; else return { st->wrappedPromptString, st->wrapPL }; } }; std::string_view currentLine = st->lines[lineIdx]; size_t numWrappingLines = calculate_nwl(st, st->lineIdx, displayedTextLength(currentLine)); // if we're operating on the current line, shun bian cache the NWL count. // we'll use this for cursor_down among other things. if(st->lineIdx == lineIdx) st->cachedNWLForCurrentLine = numWrappingLines; size_t old_NWL = calculate_nwl(st, st->lineIdx, displayedTextLength(oldLine)); auto new_wli = calculate_wli(st, st->cursor); qcmd(moveCursorLeft(9999)); ztmu_dbg("nwl: %zu, old_nwl: %zu, new_wli: %zu, old_wli: %zu\n", numWrappingLines, old_NWL, new_wli, st->wrappedLineIdx); // what we want to do here is go all the way to the bottom of the string (regardless of cursor position), and clear it. // then go up one line and repeat, basically clearing the whole thing. we don't clear lines above the cursor! { auto nwl = std::max(numWrappingLines, old_NWL); if(numWrappingLines > st->wrappedLineIdx) { // the the current position (just the vcursor): auto vcursor = getCursorPosition().y; auto tomove = nwl - st->wrappedLineIdx - 1; // ztmu_dbg("height: %zu, vc: %zu, tm: %zu\n", st->termHeight, vcursor, tomove); if(st->termHeight - vcursor < tomove) { ztmu_dbg("need to scroll\n"); // scroll the screen down -- but move the text *up* qcmd(zpr::sprint("%s%dS", CSI, tomove - (st->termHeight - vcursor))); } qcmd(moveCursorDown(tomove)); } for(size_t i = 1; i < nwl - new_wli; i++) { qcmd("\x1b[2K"); qcmd(moveCursorUp(1)); } } // move to the leftmost position. qcmd(moveCursorLeft(9999)); { // there's stuff on the left of the cursor that we need to print too, since we cleared the entire line. bool didWrap = false; size_t alrPrinted = 0; // TODO: we always use normPL here, but we should choose between normPL and contPL! auto hcursor = get_cursor_line_offset(st->termWidth, st->cursor, st->normPL, st->wrapPL, &didWrap); ztmu_dbg("didWrap: %d\n", didWrap); if(didWrap) { // we always use new_wli - 1, because we might be moving left-to-right or right-to-left! auto [ pstr, plen ] = getPromptForLine(new_wli - 1); auto leftCPs = st->termWidth - plen; auto leftByteCursor = calculate_left_codepoints(leftCPs, currentLine, st->cursor, st->byteCursor).second; auto leftPortion = currentLine.substr(leftByteCursor, st->byteCursor - leftByteCursor); currentLine.remove_prefix(st->byteCursor); // before proceeding, move the cursor up one, and to the left. qcmd(moveCursorUp(1)); qcmd(moveCursorLeft(9999)); qcmd(pstr); qcmd(leftPortion); // ok, now move the line down, and print the continuation prompt. qcmd(moveCursorDown(1)); qcmd(moveCursorLeft(9999)); qcmd(st->wrappedPromptString); alrPrinted = st->wrapPL; } else { auto [ pstr, plen ] = getPromptForLine(new_wli); auto leftCPs = hcursor - plen; auto leftByteCursor = calculate_left_codepoints(leftCPs, currentLine, st->cursor, st->byteCursor).second; // we need to print leftCPs of stuff *before* the current cursor. auto leftPortion = currentLine.substr(leftByteCursor, st->byteCursor - leftByteCursor); currentLine.remove_prefix(st->byteCursor); auto rem = displayedTextLength(currentLine); ztmu_dbg("hcursor = %zu, remaining = %zu, bc = %zu, lbc = %zu, len = %zu, line = '%.*s', pr = '%s', plen = %zu\n", hcursor, rem, st->byteCursor, leftByteCursor, currentLine.length(), static_cast(currentLine.length()), currentLine.data(), pstr.c_str(), plen); ztmu_dbg("leftportion = '%s'\n", std::string(leftPortion).c_str()); qcmd(pstr); qcmd(leftPortion); alrPrinted = plen + displayedTextLength(leftPortion); } size_t printedLines = 0; size_t remaining = displayedTextLength(currentLine); // clear to the right, just in case qcmd(zpr::sprint("%s0K", CSI)); while(remaining > 0) { // ok, now we can print the rest of the string "normally". auto adv_and_cons = [¤tLine](size_t cons) -> std::string_view { // return the view from [here, cons) -- in terms of codepoints // and advance the line by cons codepoints. size_t bytes_to_adv = 0; for(size_t i = 0; i < cons; i++) { bytes_to_adv = 1 + findEndOfUTF8CP(reinterpret_cast(currentLine.data()), bytes_to_adv); } auto ret = currentLine.substr(0, bytes_to_adv); currentLine.remove_prefix(bytes_to_adv); return ret; }; auto left = st->termWidth - (printedLines == 0 ? alrPrinted : st->wrapPL); auto todo = std::min(left, remaining); qcmd(adv_and_cons(todo)); remaining -= todo; if(remaining == 0) { // clear the rest of the line (cursor to end) if(todo != left) qcmd(zpr::sprint("%s0K", CSI)); ztmu_dbg("broke\n"); break; } // if there's more: // move the cursor down and left. qcmd(moveCursorDown(1)); qcmd(moveCursorLeft(9999)); // print the wrap prompt. qcmd(st->wrappedPromptString); printedLines += 1; } if(!skip_cursor) { // ok time to move up... we know that we padded with spaces all the way to the edge // so we can move up by printedLines, and left by width - hcursor qcmd(moveCursorUp(static_cast(printedLines))); qcmd(moveCursorLeft(9999)); qcmd(moveCursorRight(hcursor)); } ztmu_dbg("hcursor = %zu\n", hcursor); st->wrappedLineIdx = calculate_wli(st, st->cursor); ztmu_dbg("updated wli: %zu\n\n", st->wrappedLineIdx); if(defer_flush) *commandBuffer = commands; else flushcmd(); return std::make_pair(printedLines, hcursor); } } inline void refresh_line(State* st, std::string* oldLine) { // refresh the top line manually: ztmu_dbg("\n\n** refreshing line %d...\n", st->lineIdx); auto [ down, hcursor ] = _refresh_line(st, st->lineIdx, /* skip_cursor: */ false, oldLine ? *oldLine : st->lines[st->lineIdx], /* defer_flush: */ false, /* cmd_buffer: */ nullptr); down += 1; ztmu_dbg("down = %zu\n", down); // this is not re-entrant!!! auto old_wli = st->wrappedLineIdx; auto old_bcr = st->byteCursor; auto old_cur = st->cursor; size_t downAccum = 0; std::string buffer; // refresh every line including and after the current line. for(size_t i = st->lineIdx + 1; i < st->lines.size(); i++) { st->wrappedLineIdx = 0; st->byteCursor = 0; st->cursor = 0; // see if we need to scroll. note that _refresh_line will scroll for the current line -- ONLY IF IT WRAPS // but because we are drawing all lines, we need space for the next line as well. if(getCursorPosition().y == static_cast(st->termHeight)) buffer += zpr::sprint("%s1S", CSI); // one should be enough. buffer += moveCursorDown(down); downAccum += down; ztmu_dbg("** refreshing line %zu...\n", i); std::string buf; down = _refresh_line(st, i, /* skip_cursor: */ true, st->lines[i], /* defer_flush: */ true, &buf).first + 1; buffer += buf; ztmu_dbg("down = %zu\n", down); } if(downAccum > 0) { platform_write(zpr::sprint("%s%s%s%s", buffer, moveCursorUp(downAccum), moveCursorLeft(9999), moveCursorRight(hcursor))); } st->wrappedLineIdx = old_wli; st->byteCursor = old_bcr; st->cursor = old_cur; } static size_t _calculate_total_nwl_for_all_lines(State* st, size_t startingLineIdx = 0) { size_t down = 0; for(size_t i = startingLineIdx; i < st->lines.size(); i++) down += calculate_nwl(st, i, displayedTextLength(st->lines[i])); return down; } inline void touch_line(State* st) { // when we touch the line, we reset the history index. st->historyIdx = 0; } inline void cursor_home(State* st) { st->cursor = 0; st->byteCursor = 0; refresh_line(st); touch_line(st); } inline void cursor_end(State* st, bool refresh) { st->cursor = displayedTextLength(getCurLine(st)); st->byteCursor = getCurLine(st).size(); if(refresh) refresh_line(st); touch_line(st); } // note: internal code doesn't use delete_left or delete_right, so we don't need two // versions that handle lines. inline void delete_left(State* st) { touch_line(st); if(st->cursor > 0 && getCurLine(st).size() > 0) { auto x = st->byteCursor - 1; auto l = findBeginningOfUTF8CP(reinterpret_cast(getCurLine(st).c_str()), x); auto old = getCurLine(st); getCurLine(st).erase(l, x - l + 1); st->byteCursor -= (x - l + 1); st->cursor -= 1; refresh_line(st, &old); } else if(st->lineIdx > 0) { st->lineIdx -= 1; st->cursor = displayedTextLength(st->lines[st->lineIdx]); st->byteCursor = st->lines[st->lineIdx].size(); st->wrappedLineIdx = calculate_wli(st, st->cursor); // here's the thing: the remaining pieces of this line needs to be appended // to the previous line! (+1 here cos we already -= 1 above) auto remaining = st->lines[st->lineIdx + 1]; st->lines[st->lineIdx].insert(st->byteCursor, remaining); // before we refresh, we need to go all the way to the bottom and erase the last physical line, // so that it won't be lingering later on. { auto down = _calculate_total_nwl_for_all_lines(st, st->lineIdx) - 2; ztmu_dbg("** down = %zu\n", down); // physical cursor needs to move up one, so move up one more than we moved down. platform_write(zpr::sprint("%s%s2K%s", moveCursorDown(down), CSI, moveCursorUp(down + 1))); } // then we need to erase this line from the lines! st->lines.erase(st->lines.begin() + st->lineIdx + 1); // need to refresh. refresh_line(st); } } inline void delete_right(State* st) { touch_line(st); if(st->byteCursor < getCurLine(st).size()) { auto x = st->byteCursor; auto l = findEndOfUTF8CP(reinterpret_cast(getCurLine(st).c_str()), x); auto old = getCurLine(st); getCurLine(st).erase(x, l - x + 1); // both cursors remain unchanged. refresh_line(st, &old); } else if(st->lineIdx + 1 < st->lines.size()) { // we don't move anything. all the text from the next line gets appended to the current line. auto nextLine = st->lines[st->lineIdx + 1]; st->lines[st->lineIdx].insert(st->byteCursor, nextLine); // before we refresh, we need to go all the way to the bottom and erase the last physical line, // so that it won't be lingering later on. { auto down = _calculate_total_nwl_for_all_lines(st, st->lineIdx) - 1; platform_write(zpr::sprint("%s%s2K%s", moveCursorDown(down), CSI, moveCursorUp(down))); } // then we need to erase the next line from the lines! st->lines.erase(st->lines.begin() + st->lineIdx + 1); // need to refresh. refresh_line(st); } } // bound to C-k by default static void delete_line_right(State* st) { touch_line(st); if(st->byteCursor < st->lines[st->lineIdx].size()) { st->lines[st->lineIdx].erase(st->byteCursor); refresh_line(st); } else if(st->lineIdx + 1 < st->lines.size()) { // just call delete_right, which will collapse this line. delete_right(st); } } // we differentiate between _cursor_left() and cursor_left() -- the latter only moves along // a single line ("logical line"), while the latter will move to the previous line if the current // line is exhausted. user-inputs call cursor_left(), while internal users should call _cursor_left(). static void _cursor_left(State* st, size_t n, bool refresh = true) { touch_line(st); for(size_t i = 0; i < n; i++) { if(st->cursor > 0) { auto x = st->byteCursor - 1; auto l = findBeginningOfUTF8CP(reinterpret_cast(getCurLine(st).c_str()), x); st->byteCursor -= (x - l + 1); st->cursor -= 1; } } if(refresh) refresh_line(st); } inline void cursor_left(State* st, bool refresh) { touch_line(st); if(st->cursor > 0) { _cursor_left(st, 1, refresh); } else if(st->lineIdx > 0) { st->lineIdx -= 1; // physical cursor needs to move up one. platform_write(moveCursorUp(1)); st->cursor = displayedTextLength(st->lines[st->lineIdx]); st->byteCursor = st->lines[st->lineIdx].size(); st->wrappedLineIdx = calculate_wli(st, st->cursor); // need to refresh. refresh_line(st); } } // same deal with _cursor_right as for _cursor_left. static void _cursor_right(State* st, size_t n, bool refresh = true) { touch_line(st); for(size_t i = 0; i < n; i++) { if(st->byteCursor < getCurLine(st).size()) { auto x = st->byteCursor; auto l = findEndOfUTF8CP(reinterpret_cast(getCurLine(st).c_str()), x); st->byteCursor += (l - x + 1); st->cursor += 1; } } if(refresh) refresh_line(st); } inline void cursor_right(State* st, bool refresh) { touch_line(st); if(st->byteCursor < getCurLine(st).size()) { _cursor_right(st, 1, refresh); } else if(st->lineIdx + 1 < st->lines.size()) { st->lineIdx += 1; // physical cursor needs to move down one. platform_write(moveCursorDown(1)); st->cursor = 0; st->byteCursor = 0; st->wrappedLineIdx = 0; // need to refresh. refresh_line(st); } } // shared stuff that history-manipulating people need to do, basically moving the // cursor all the way to the end of the text, including the physical cursor. static void _move_cursor_to_end_of_input(State* st) { // we want the cursor to be at the very end of the last line of input! // but first, go to the very beginning, and refresh -- this draws all the lines. st->lineIdx = 0; st->cursor = 0; st->byteCursor = 0; st->wrappedLineIdx = 0; refresh_line(st); // then we can move to the bottom and refresh again. { size_t down = _calculate_total_nwl_for_all_lines(st) - 1; platform_write(moveCursorDown(down)); } st->cursor = displayedTextLength(st->lines.back()); st->byteCursor = convertCursorToByteCursor(st->lines.back().c_str(), st->cursor); st->lineIdx = st->lines.size() - 1; st->wrappedLineIdx = calculate_wli(st, st->cursor); refresh_line(st); } inline void cursor_up(State* st) { if(st->cursor > 0 && st->wrappedLineIdx > 0) { touch_line(st); size_t promptL = st->lineIdx == 0 ? st->normPL : st->contPL; // first, get the current horz cursor position: auto hcursor = get_cursor_line_offset(st->termWidth, st->cursor, promptL, st->wrapPL); // because wrappedLineIdx > 0, we know we're wrapping. this is the number of chars on the current // line (of text!), to the left of the cursor. auto h_curlength = hcursor - st->wrapPL; // this is how many extra chars to go left. auto rightmargin = st->termWidth - hcursor; // this will stop when we can't go further, so there's no need to limit. _cursor_left(st, h_curlength + rightmargin); /* so what we want to do, ideally, is move "left" termWidth number of codepoints. HOWEVER, if we have such a situation: * > some long str | ing ^ if the cursor is there and we want to go "up", what ought to happen is that the cursor gets moved to the left extreme -- ie. before the "s" in "some". we will make and document an assumption here: all the wrapped prompts are the same length, and the only situation where you get this problem is when you move from the second line up to the first line. thus, we can use the length of the string, without having to do stupid weird math to figure out how many chars are on the previous line. */ } else if(st->lineIdx > 0) { touch_line(st); // ok -- we are now into weird strange territory. move up into the previous continuation line... ztmu_dbg("going up...\n"); std::string_view prevLine = st->lines[st->lineIdx - 1]; size_t prevLineLen = displayedTextLength(prevLine); // first, get the current horz cursor position. for the current line, we must always be // in a continuation if are able to go upwards. auto hcursor = get_cursor_line_offset(st->termWidth, st->cursor, st->contPL, st->wrapPL); // now, we get the offset of the previous line: auto prev_hcursor = get_cursor_line_offset(st->termWidth, prevLineLen, st->lineIdx > 1 ? st->contPL : st->normPL, st->wrapPL); auto prev_right_margin = st->termWidth - prev_hcursor; st->cursor = prevLineLen; st->byteCursor = convertCursorToByteCursor(prevLine.data(), st->cursor); ztmu_dbg("c: %zu, bc: %zu, margin: %zu, pl: '%s'\n", st->cursor, st->byteCursor, prev_right_margin, std::string(prevLine).c_str()); st->lineIdx -= 1; st->wrappedLineIdx = calculate_wli(st, st->cursor); // and then we move the cursor. platform_write(moveCursorUp(1)); _cursor_left(st, st->termWidth - hcursor - prev_right_margin, /* refresh: */ false); refresh_line(st); ztmu_dbg("c: %zu, bc: %zu, margin: %zu, pl: '%s'\n", st->cursor, st->byteCursor, prev_right_margin, std::string(prevLine).c_str()); } else if(st->history.size() > 0 && st->historyIdx < st->history.size()) { ztmu_dbg("## history up (%zu)\n", st->historyIdx); // save it, so we can go back to it. if(st->historyIdx == 0) st->savedCurrentInput = st->lines; // ok, so we're already at the top of the thing, so we should clear the screen from here // to the bottom. platform_write(zpr::sprint("%s0J", CSI)); // set the index, set the lines, and refresh. st->historyIdx += 1; st->lines = st->history[st->history.size() - st->historyIdx]; ztmu_dbg("setting: \n"); for(const auto& l : st->lines) ztmu_dbg("'%s'\n", l); ztmu_dbg("\n"); _move_cursor_to_end_of_input(st); } } inline void cursor_down(State* st) { if(st->byteCursor < getCurLine(st).size() && (st->lines.size() == 1 || st->wrappedLineIdx + 1 < st->cachedNWLForCurrentLine)) { touch_line(st); // works on a similar principle as cursor_up. auto hcursor = get_cursor_line_offset(st->termWidth, st->cursor, st->lineIdx == 0 ? st->normPL : st->contPL, st->wrapPL); // again, we make a similar assumption -- that only the first and second prompts can differ; the second and // subsequent wrapping prompts must have the same length. auto rightmargin = st->termWidth - hcursor; // in the next line, the prompt will always be a wrapping prompt. auto leftmargin = hcursor - st->wrapPL; _cursor_right(st, rightmargin + leftmargin); } else if(st->lineIdx + 1 < st->lines.size()) { touch_line(st); ztmu_dbg("going down...\n"); std::string_view nextLine = st->lines[st->lineIdx + 1]; size_t nextLineLen = displayedTextLength(nextLine); // first, get the current horz cursor position: auto hcursor = get_cursor_line_offset(st->termWidth, st->cursor, st->lineIdx == 0 ? st->normPL: st->contPL, st->wrapPL); // ok, the next line will definitely be a continuation prompt. so, see how many chars into the line // we'll actually put ourselves -- and handle the edge case of negative values! auto next_leftChars = (hcursor < st->contPL ? 0 // snap to the beginning of the line, then. : std::min(hcursor - st->contPL, nextLineLen) ); // ok, time to do the real work. st->cursor = next_leftChars; st->byteCursor = convertCursorToByteCursor(nextLine.data(), st->cursor); st->lineIdx += 1; // now move the cursor and refresh! platform_write(moveCursorDown(1)); refresh_line(st); } else if(st->historyIdx > 0) { ztmu_dbg("## history down (%zu)\n", st->historyIdx); // somewhat similar to moving up in history. first, we will already be at the bottom of // all lines. so, we need to move the physical and virtual cursor to the top of the entire // input. to do this, calculate the total NWL of all lines: { // we must do this for the current input state, before we change into the history. auto up = _calculate_total_nwl_for_all_lines(st) - 1; // as we move up, we must clear the entire line, to get rid of the lingering text. for(size_t i = 0; i < up; i++) { platform_write(zpr::sprint("%s2K", CSI)); platform_write(moveCursorUp(1)); } } // ok, now we can change: st->historyIdx -= 1; if(st->historyIdx == 0) st->lines = st->savedCurrentInput, st->savedCurrentInput.clear(); else st->lines = st->history[st->history.size() - st->historyIdx]; // now, fix it. _move_cursor_to_end_of_input(st); } } // this is ugly!!! inline bool read_line(State* st, int promptMode, std::string seed) { constexpr char CTRL_A = '\x01'; constexpr char CTRL_C = '\x03'; constexpr char CTRL_D = '\x04'; constexpr char CTRL_E = '\x05'; constexpr char CTRL_H = '\x08'; constexpr char CTRL_K = '\x0B'; constexpr char ENTER = '\x0D'; constexpr char BACKSPACE = '\x7F'; // NOT THREAD SAFE!! enterRawMode(); currentStateForSignal = st; st->termWidth = getTerminalWidth(); st->termHeight = getTerminalHeight(); st->wrappedLineIdx = 0; { // TODO: fix this. probably pull out calc_wli from the refresh function. // if your seed exceeds the terminal width, then you deserve it. st->lines.push_back(seed); st->cursor = seed.size(); st->byteCursor = convertCursorToByteCursor(seed.c_str(), st->cursor); } platform_write(promptMode == 0 ? st->promptString : st->contPromptString); platform_write(seed); bool didSetSignalHandler = setup_sigwinch(); auto commit_line = [&](bool refresh = true) { // move the cursor to the end, refresh the line, then leave raw mode -- this makes sure // that we leave the cursor in a nice place after the call to this function returns. cursor_end(st, refresh); // see how many lines we need to go down. size_t down = 0; for(size_t i = st->lineIdx + 1; i < st->lines.size(); i++) down += calculate_nwl(st, i, displayedTextLength(st->lines[i])); platform_write(moveCursorDown(down)); platform_write(moveCursorLeft(9999)); }; st->wasAborted = false; bool eof = false; while(true) { // lol loop_top: char c = 0; if(platform_read_one(&c) <= 0) break; ztmu_dbg("[%d]", static_cast(c)); switch(c) { case CTRL_C: { st->wasAborted = true; if(st->lines.size() == 1 && st->lines[0].empty()) { if(st->emptyCtrlCExits) { st->wasAborted = true; eof = true; goto finish; } else { platform_write(st->uselessControlCMsg); goto finish_now; } } else { commit_line(/* refresh: */ false); // if we are multi-line, we can return eof. if not, just return empty. if(st->lines.size() > 1) eof = true; st->clear(); // to prevent fuckery, we need to add an empty line back in! st->lines.push_back(""); goto finish_now; } } // this is a little complex; control-D is apparently both EOF: when the buffer is empty, // and delete-left: when it is not... case CTRL_D: { // if the buffer is empty, then quit. if(getCurLine(st).empty() && st->lineIdx == 0) { st->wasAborted = true; eof = true; goto finish; } else { delete_right(st); } } break; case CTRL_A: { cursor_home(st); } break; case CTRL_E: { cursor_end(st); } break; // backspace case CTRL_H: [[fallthrough]]; case BACKSPACE: { delete_left(st); } break; case CTRL_K: { // delete to end of line. delete_line_right(st); } break; // enter case ENTER: { if(auto fn = st->keyHandlers[Key::ENTER]; fn) { auto res = fn(st, Key::ENTER); switch(res) { case HandlerAction::CONTINUE: goto loop_top; case HandlerAction::QUIT: eof = true; goto finish; default: break; } } goto finish; } // time for some fun. case ESC: { // there should be at least two more! char seq[2]; platform_read(seq, 2); char thing = 0; if(seq[0] == '[') { if(seq[1] >= '0' && seq[1] <= '9') { int n = 0; // ok now time to read until a ~ char x = seq[1]; while(x >= '0' && x <= '9') { n = (10 * n) + (x - '0'); platform_read_one(&x); } // we have a modifier -- for now, ignore them. if(x == ';') { // advance it. platform_read_one(&x); int mods = 0; while(x >= '0' && x <= '9') { mods = (10 * mods) + (x - '0'); platform_read_one(&x); } thing = x; } else { thing = static_cast(n); } if(n == 200) { ztmu_dbg("PASTE!\n"); // keep reading until we find an esc. std::string pasted; char x = 0; while(platform_read_one(&x) > 0) { pasted += x; if(pasted.rfind("\x1b[201~") != std::string::npos) break; } // get rid of the thing at the end. pasted.erase(pasted.rfind("\x1b[201~")); ztmu_dbg("PASTED: '%s'\n", pasted); auto oldline = getCurLine(st); auto len = displayedTextLength(pasted); getCurLine(st).insert(st->byteCursor, pasted); st->cursor += len; st->byteCursor += pasted.size(); ztmu_dbg("c: %zu, bc: %zu\n", st->cursor, st->byteCursor); refresh_line(st, &oldline); goto loop_top; } } else { thing = seq[1]; } switch(thing) { case 3: delete_right(st); break; case 1: cursor_home(st); break; case 7: cursor_home(st); break; case 4: cursor_end(st); break; case 8: cursor_end(st); break; case 'A': cursor_up(st); break; case 'B': cursor_down(st); break; case 'C': cursor_right(st); break; case 'D': cursor_left(st); break; case 'H': cursor_home(st); break; case 'F': cursor_end(st); break; } } else if(seq[0] == 'O') { if(seq[1] == 'H') cursor_home(st); else if(seq[1] == 'F') cursor_end(st); } } break; // default: just append -- if it's not a control char. default: { auto old = getCurLine(st); uint8_t uc = static_cast(c); // also: for handlers, we don't bother about giving you codepoints, so... tough luck. // TODO. if(auto fn = st->keyHandlers[static_cast(uc)]; fn) { switch(fn(st, static_cast(uc))) { case HandlerAction::CONTINUE: break; case HandlerAction::QUIT: eof = true; [[fallthrough]]; case HandlerAction::RETURN: [[fallthrough]]; default: goto finish; } } if(uc >= 0x20 && uc <= 0x7F) { getCurLine(st).insert(getCurLine(st).begin() + st->byteCursor, c); st->cursor += 1; st->byteCursor += 1; } else if(uc >= 0x20) { std::string cp; cp += c; // if it's unicode, then try and read even more. // see: https://en.wikipedia.org/wiki/UTF-8 for the bitmasks we're using. if((uc & 0xE0) == 0xC0) { // one extra byte char c = 0; platform_read_one(&c); cp += c; } else if((uc & 0xF0) == 0xE0) { // two extra bytes char buf[2]; platform_read(buf, 2); cp += buf; } else if((uc & 0xF8) == 0xF0) { // three extra bytes char buf[3]; platform_read(buf, 3); cp += buf; } getCurLine(st).insert(st->byteCursor, cp); st->byteCursor += cp.size(); st->cursor += displayedTextLength(cp); } refresh_line(st, &old); } break; } } finish: commit_line(); finish_now: // restore the signal state, and reset the terminal to normal mode. currentStateForSignal = 0; if(didSetSignalHandler) restore_sigwinch(); leaveRawMode(); platform_write("\n"); return eof; } std::vector pretty_print_text_block(const std::vector& paragraphs, const char* leftMargin, const char* rightMargin, size_t maxLines) { auto split_words = [](const std::string& s) -> std::vector { std::vector ret; size_t word_start = 0; for(size_t i = 0; i < s.size(); i++) { if(s[i] == ' ') { ret.push_back(std::string_view(s.c_str() + word_start, i - word_start)); word_start = i + 1; } else if(s[i] == '-') { ret.push_back(std::string_view(s.c_str() + word_start, i - word_start + 1)); word_start = i + 1; } } ret.push_back(std::string_view(s.c_str() + word_start)); return ret; }; auto tw = ztmu::getTerminalWidth(); tw = std::min(tw, tw - strlen(leftMargin) - strlen(rightMargin)); auto disp_len = ztmu::displayedTextLength; std::vector output; size_t lines = 1; size_t paras = 0; for(auto& l : paragraphs) { size_t remaining = tw; // sighs. auto ss = std::stringstream(); ss << leftMargin; // each "line" is actually a paragraph. we want to be nice, so pad on the right by a few spaces // and hyphenate split words. // first split into words auto words = split_words(l); for(const auto& word : words) { if(maxLines > 0 && lines == maxLines && remaining <= word.size() + 4) { // don't. just quit. ss << "..."; break; } auto len = disp_len(word); if(remaining >= len) { ss << word << (word.back() != '-' ? " " : ""); remaining -= len; if(remaining > 0) { remaining -= 1; } else { ss << "\n" << leftMargin; lines++; remaining = tw; } } else if(remaining < 3 || len < 5) { // for anything less than 5 chars, put it on the next line -- don't hyphenate. ss << "\n" << leftMargin << word << (word.back() != '-' ? " " : ""); remaining = tw - (len + 1); lines++; } else { auto thisline = remaining - 2; // if we end up making a fragment 3 letters or shorter, // push it to the next line instead. if(std::min(word.size(), thisline ) <= 3) { thisline = 0; ss << "\n" << leftMargin << word << (word.back() != '-' ? " " : ""); } else { // split it. ss << word.substr(0, thisline) << "-" << "\n"; ss << leftMargin << word.substr(thisline) << " "; } remaining = tw - word.substr(thisline).size(); lines++; } } output.push_back(ss.str()); // if the paragraph has some space remaining at the end, then // don't print the next one, just stop here. if(maxLines > 0 && lines == maxLines && paras < paragraphs.size()) break; paras++; } return output; } } } #endif namespace ztmu { inline std::vector prettyFormatTextBlock(const std::vector& paragraphs, const char* leftMargin, const char* rightMargin, size_t maxLines) { return detail::pretty_print_text_block(paragraphs, leftMargin, rightMargin, maxLines); } inline std::vector prettyFormatTextBlock(const std::string& block, const char* leftMargin, const char* rightMargin, size_t maxLines) { auto splitString = [](std::string_view view, char delim = '\n') -> std::vector { std::vector ret; while(true) { size_t ln = view.find(delim); if(ln != std::string_view::npos) { ret.emplace_back(view.data(), ln); view.remove_prefix(ln + 1); } else { break; } } // account for the case when there's no trailing newline, and we still have some stuff stuck in the view. if(!view.empty()) ret.emplace_back(view.data(), view.length()); return ret; }; std::vector paragraphs; auto splits = splitString(block); for(auto sv : splits) { auto s = std::string(sv); s.erase(std::remove(s.begin(), s.end(), '\r')); if(!s.empty()) paragraphs.push_back(s); } return detail::pretty_print_text_block(paragraphs, leftMargin, rightMargin, maxLines); } inline size_t displayedTextLength(const std::string_view& str) { return detail::displayedTextLength(str); } inline size_t getTerminalWidth() { return detail::getTerminalWidth(); } inline void State::setupConsole() { detail::setup_console(); } inline void State::unsetupConsole() { detail::unsetup_console(); } inline void State::clear() { // reset the thing. this->savedCurrentInput.clear(); this->lines.clear(); this->lineIdx = 0; this->cachedNWLForCurrentLine = 0; this->wrappedLineIdx = 0; // we call clear on commit, so the history index needs to go back to 0. this->historyIdx = 0; } inline void State::setPrompt(const std::string& prompt) { this->promptString = prompt; this->normPL = detail::displayedTextLength(prompt); } inline void State::setContPrompt(const std::string& prompt) { this->contPromptString = prompt; this->contPL = detail::displayedTextLength(prompt); } inline void State::setWrappedPrompt(const std::string& prompt) { this->wrappedPromptString = prompt; this->wrapPL = detail::displayedTextLength(prompt); } inline void State::move_cursor_left(int n) { if(n < 0) move_cursor_right(-n); for(int i = 0; i < n; i++) detail::cursor_left(this, /* refresh: */ false); detail::refresh_line(this); } inline void State::move_cursor_right(int n) { if(n < 0) move_cursor_left(-n); for(int i = 0; i < n; i++) detail::cursor_right(this, /* refresh: */ false); detail::refresh_line(this); } inline void State::move_cursor_up(int n) { if(n < 0) move_cursor_down(-n); for(int i = 0; i < n; i++) detail::cursor_up(this); detail::refresh_line(this); } inline void State::move_cursor_down(int n) { if(n < 0) move_cursor_up(-n); for(int i = 0; i < n; i++) detail::cursor_down(this); detail::refresh_line(this); } inline void State::move_cursor_home() { detail::cursor_home(this); } inline void State::move_cursor_end() { detail::cursor_end(this); } inline void State::delete_left(int n) { if(n <= 0) return; for(int i = 0; i < n; i++) detail::delete_left(this); } inline void State::delete_right(int n) { if(n <= 0) return; for(int i = 0; i < n; i++) detail::delete_right(this); } inline void State::setKeyHandler(Key k, std::function handler) { this->keyHandlers[k] = handler; } inline void State::unsetKeyHandler(Key k) { this->keyHandlers[k] = std::function(); } inline std::string State::getCurrentLine() { return this->lines[this->lineIdx]; } inline void State::setCurrentLine(const std::string& s) { auto old = this->lines[this->lineIdx]; this->lines[this->lineIdx] = s; // we need to ensure the cursors are updated! this->cursor = std::min(this->cursor, detail::displayedTextLength(s)); this->byteCursor = detail::convertCursorToByteCursor(s.c_str(), this->cursor); detail::refresh_line(this, &old); } inline void State::useUniqueHistory(bool enable) { this->uniqueHistory = enable; } // your responsibility to check if the input was empty! // well if you unique it then you'll only get one empty history entry, but still. inline void State::addPreviousInputToHistory() { if(this->wasAborted) return; // now, if we need to unique the history, then erase (if any) the // prior occurrence of that item. we shouldn't really need to check for more // than one, because any previous call to addHistory() should have already // left us with at most two. // obviously, we check for dupes before adding the current entry, because then we'll // just end up erasing the new entry like an idiot. if(auto it = std::find(this->history.begin(), this->history.end(), this->lines); it != this->history.end()) this->history.erase(it); // this must be called before the next invocation of read() or readContinuation() // so that State->lines is still preserved. this->history.push_back(this->lines); } inline void State::loadHistory(const std::vector>& h) { this->historyIdx = 0; this->history = h; } // it's up to you to serialise it! inline std::vector> State::getHistory() { return this->history; } inline void State::setMessageOnControlC(const std::string& msg) { this->uselessControlCMsg = msg; } inline void State::enableExitOnEmptyControlC() { this->emptyCtrlCExits = true; } inline std::optional State::read() { // clear. this->clear(); bool eof = detail::read_line(this, /* promptMode: */ 0, ""); if(eof) return std::nullopt; else return this->lines.back(); } inline std::optional> State::readContinuation(const std::string& seed) { // don't clear this->lineIdx++; bool eof = detail::read_line(this, /* promptMode: */ 1, seed); if(eof) return std::nullopt; else return this->lines; } } ================================================ FILE: source/main.cpp ================================================ // main.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "defs.h" #include "repl.h" #include "errors.h" #include "backend.h" #include "frontend.h" #include "ir/module.h" #include "ir/interp.h" #include "memorypool.h" #include "allocator.h" #include struct timer { using hrc = std::chrono::high_resolution_clock; timer() : out(nullptr) { start = hrc::now(); } explicit timer(double* t) : out(t) { start = hrc::now(); } ~timer() { if(out) *out = static_cast((hrc::now() - start).count()) / 1000000.0; } double measure() { return static_cast((hrc::now() - start).count()) / 1000000.0; } double* out = 0; std::chrono::time_point start; }; static void compile(std::string in, std::string out) { auto start_time = std::chrono::high_resolution_clock::now(); double lexer_ms = 0; double parser_ms = 0; double typecheck_ms = 0; double codegen_ms = 0; timer total; auto printStats = [&total](const std::string& name) { if(frontend::getPrintProfileStats()) { debuglogln("%-9s (%.1f ms)\t[w: %.1fk, f: %.1fk, a: %.1fk]", name, total.measure(), mem::getWatermark() / 1024.0, mem::getDeallocatedCount() / 1024.0, mem::getAllocatedCount() / 1024.0); } }; auto cd = backend::CompiledData(); { frontend::CollectorState state; sst::DefinitionTree* dtree = 0; { timer t(&lexer_ms); frontend::collectFiles(in, &state); printStats("lex"); } { timer t(&parser_ms); frontend::parseFiles(&state); printStats("parse"); } { timer t(&typecheck_ms); dtree = frontend::typecheckFiles(&state); printStats("typecheck"); } { timer t(&codegen_ms); iceAssert(dtree); auto module = frontend::generateFIRModule(&state, dtree); module->finaliseGlobalConstructors(); printStats("codegen"); // if we requested to dump, then dump the IR here. if(frontend::getPrintFIR()) fprintf(stderr, "%s\n", module->print().c_str()); cd.module = module; } // delete *most* of the memory we've allocated. obviously IR values need to stay alive, // since we haven't run the backend yet. so this just kills the AST and SST values. util::clearAllPools(); printStats("free_mem"); // print the final stats. if(frontend::getPrintProfileStats()) { auto compile_ms = static_cast((std::chrono::high_resolution_clock::now() - start_time).count()) / 1000.0 / 1000.0; debuglogln("%-9s (%.1f ms)\t[lex: %.1f, parse: %.1f, typechk: %.1f, codegen: %.1f]", "compile", compile_ms, lexer_ms, parser_ms, typecheck_ms, codegen_ms); debuglogln("processed: %d lines, %.2f loc/s, %d fir values\n", state.totalLinesOfCode, static_cast(state.totalLinesOfCode) / (compile_ms / 1000.0), fir::Value::getCurrentValueId()); } } iceAssert(cd.module); { #if !OS_DARWIN if(frontend::getFrameworksToLink().size() > 0 || frontend::getFrameworkSearchPaths().size() > 0) error("backend: frameworks are only supported on Darwin"); #endif using namespace backend; Backend* backend = Backend::getBackendFromOption(frontend::getBackendOption(), cd, { in }, out); if(backend == 0) return; int _capsneeded = 0; { if(frontend::getOutputMode() == ProgOutputMode::RunJit) _capsneeded |= BackendCaps::JIT; if(frontend::getOutputMode() == ProgOutputMode::ObjectFile) _capsneeded |= BackendCaps::EmitObject; if(frontend::getOutputMode() == ProgOutputMode::Program) _capsneeded |= BackendCaps::EmitProgram; } auto capsneeded = static_cast(_capsneeded); if(backend->hasCapability(capsneeded)) { backend->performCompilation(); backend->optimiseProgram(); backend->writeOutput(); } else { error("selected backend '%s' does not have some required capabilities (missing %s)\n", backend->str(), capabilitiesToString(capsneeded)); } } } int main(int argc, char** argv) { platform::setupCrashHandlers(); platform::setupTerminalIfNecessary(); platform::compiler::performSelfDlOpen(); auto [ input_file, output_file ] = frontend::parseCmdLineOpts(argc, argv); if(frontend::getIsReplMode()) repl::start(); else compile(input_file, output_file); return 0; } ================================================ FILE: source/misc/allocator.cpp ================================================ // allocator.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include #include "defs.h" #include "allocator.h" #include "platform.h" #if OS_WINDOWS #define WIN32_LEAN_AND_MEAN 1 #ifndef NOMINMAX #define NOMINMAX #endif #include #else #include #include #include #endif namespace mem { static void* _alloc(size_t bytes) { #if OS_WINDOWS auto ret = VirtualAlloc(nullptr, bytes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if(ret == nullptr) _error_and_exit("failed to allocate %d bytes of memory (large page min: %d)\n", bytes, GetLargePageMinimum()); return ret; #else auto ret = mmap(nullptr, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if(ret == nullptr || reinterpret_cast(ret) == static_cast(-1)) _error_and_exit("failed to allocate %d bytes of memory\n", bytes); return ret; #endif } static void _dealloc(void* ptr, size_t bytes) { #if OS_WINDOWS VirtualFree(ptr, 0, MEM_RELEASE); #else munmap(ptr, bytes); #endif } static size_t allocated_count = 0; static size_t freed_count = 0; static size_t watermark = 0; void* allocate_memory(size_t bytes) { watermark += bytes; allocated_count += bytes; return _alloc(bytes); } void deallocate_memory(void* ptr, size_t bytes) { watermark -= bytes; freed_count += bytes; _dealloc(ptr, bytes); } void resetStats() { allocated_count = 0; freed_count = 0; watermark = 0; } size_t getAllocatedCount() { return allocated_count; } size_t getDeallocatedCount() { return freed_count; } size_t getWatermark() { return watermark; } } ================================================ FILE: source/misc/destructors.cpp ================================================ // destructors.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" namespace ast { Stmt::~Stmt() { } Expr::~Expr() { } } ================================================ FILE: source/misc/identifier.cpp ================================================ // identifier.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "defs.h" #include "sst.h" #include "frontend.h" #include "ir/type.h" sst::Stmt* TCResult::stmt() const { if(this->_kind == RK::Error) { this->_pe->postAndQuit(); // throw ErrorException(this->_pe); } switch(this->_kind) { case RK::Statement: return this->_st; case RK::Expression: return this->_ex; case RK::Definition: return this->_df; default: _error_and_exit("not stmt\n"); } } sst::Expr* TCResult::expr() const { if(this->_kind == RK::Error) { this->_pe->postAndQuit(); // throw ErrorException(this->_pe); } if(this->_kind != RK::Expression) _error_and_exit("not expr\n"); return this->_ex; } sst::Defn* TCResult::defn() const { if(this->_kind == RK::Error) { this->_pe->postAndQuit(); // throw ErrorException(this->_pe); } if(this->_kind != RK::Definition) _error_and_exit("not defn\n"); return this->_df; } void PolyArgMapping_t::add(const std::string& name, pts::Type* t) { SingleArg arg; arg.name = name; arg.type = t; arg.index = static_cast(-1); this->maps.push_back(arg); } void PolyArgMapping_t::add(size_t idx, pts::Type* t) { SingleArg arg; arg.name = ""; arg.type = t; arg.index = idx; this->maps.push_back(arg); } bool Identifier::operator == (const Identifier& other) const { return (other.name == this->name) && (other.str() == this->str()); } bool Identifier::operator != (const Identifier& other) const { return !(other == *this); } std::string Identifier::str() const { std::string ret; for(const auto& s : this->scope.components()) ret += s + "."; ret += this->name; if(this->kind == IdKind::Function) { ret += "("; for(const auto& p : this->params) ret += p->str() + ", "; if(this->params.size() > 0) ret.pop_back(), ret.pop_back(); ret += ")"; } return ret; } fir::Name Identifier::convertToName() const { switch(this->kind) { case IdKind::Name: return fir::Name::of(this->name, this->scope.components()); case IdKind::Type: return fir::Name::type(this->name, this->scope.components()); case IdKind::Function: return fir::Name::function(this->name, this->scope.components(), this->params, this->returnType); default: iceAssert(0 && "invalid identifier"); } } std::string Location::toString() const { return strprintf("(%s:%d:%d)", frontend::getFilenameFromID(this->fileID), this->line + 1, this->col + 1); } std::string Location::shortString() const { return strprintf("(%s:%d:%d)", frontend::getFilenameFromPath(frontend::getFilenameFromID(this->fileID)), this->line + 1, this->col + 1); } namespace util { std::string typeParamMapToString(const std::string& name, const TypeParamMap_t& map) { if(map.empty()) return name; std::string ret; for(auto m : map) ret += (m.first + ":" + m.second->encodedStr()) + ","; // shouldn't be empty. iceAssert(ret.size() > 0); return strprintf("%s<%s>", name, ret.substr(0, ret.length() - 1)); } } namespace zpr { std::string print_formatter::print(const Identifier& x, const format_args&) { return x.str(); } std::string print_formatter::print(const VisibilityLevel& x, const format_args&) { switch(x) { case VisibilityLevel::Invalid: return "invalid"; case VisibilityLevel::Public: return "public"; case VisibilityLevel::Private: return "private"; case VisibilityLevel::Internal: return "internal"; default: return "unknown"; } } } ================================================ FILE: source/misc/mpool.cpp ================================================ // mpool.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "defs.h" #include "memorypool.h" #include namespace util { static std::unordered_set pools; void addPool(MemoryPool_base* pool) { pools.insert(pool); } void clearAllPools() { for(auto pool : pools) pool->clear(); } } ================================================ FILE: source/platform/backtrace.cpp ================================================ // backtrace.cpp // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. #include #include "errors.h" #include "platform.h" #if OS_DARWIN #include // note: we declare these ourselves because there's some issue with execinfo.h on osx ): extern "C" { int backtrace(void**, int); char** backtrace_symbols(void* const*, int); } #elif OS_UNIX #include #include #endif namespace platform { constexpr size_t MAX_FRAMES = 128; constexpr size_t SKIP_FRAMES = 1; struct piece_t { size_t num; uintptr_t address; size_t offset; std::string modName; std::string mangledName; std::string demangledName; }; void printStackTrace() { #if OS_WINDOWS #else void* arr[MAX_FRAMES] { }; size_t num = backtrace(arr, MAX_FRAMES); char** strs = backtrace_symbols(arr, num); std::vector pieces; for(size_t i = SKIP_FRAMES; i < num; i++) { // platform-specific output! if constexpr (OS_DARWIN) { piece_t piece; piece.num = i; char modname[1024] { }; char funcname[1024] { }; sscanf(strs[i], "%*s %s %zx %s %*s %zu", &modname[0], &piece.address, &funcname[0], &piece.offset); piece.mangledName = funcname; piece.modName = modname; if(piece.mangledName.find("_Z") == 0) { int status = -1; char* demangledName = abi::__cxa_demangle(piece.mangledName.c_str(), nullptr, nullptr, &status); if(status == 0) { std::string deman = demangledName; free(demangledName); // do replacements. std::map replacements = { { "std::__1::basic_string, std::__1::allocator >", "std::string" } }; for(const auto& [ from, to ] : replacements) { size_t it = -1; while((it = deman.find(from)) != std::string::npos) deman.replace(it, from.size(), to); } piece.demangledName = deman; } else { piece.demangledName = "??"; } // skip some. if(piece.demangledName == "sst::Stmt::codegen(cgn::CodegenState*, fir::Type*)") continue; } else { piece.demangledName = piece.mangledName; } debuglogln(" %2d: %12x | %s + %#x", piece.num, piece.address, piece.demangledName, piece.offset); } else { // TODO. } } #endif } } ================================================ FILE: source/platform/compiler.cpp ================================================ // compiler.cpp // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. #include #include "errors.h" #include "frontend.h" #if OS_WINDOWS #define WIN32_LEAN_AND_MEAN 1 #ifndef NOMINMAX #define NOMINMAX #endif #include #else #include #include #include #include #endif namespace platform { namespace compiler { #if OS_WINDOWS static HMODULE currentModule = 0; static std::vector otherModules; static std::vector loadedDllDirs; #else void* currentModule = 0; #endif std::string getCompilerCommandLine(const std::vector& inputObjects, const std::string& outputFilename) { std::string cmdline; #if OS_WINDOWS // TODO: get set the target properly!! // TODO: get set the target properly!! // TODO: get set the target properly!! cmdline = strprintf("%s\\x64\\link.exe /nologo /incremental:no /out:%s /nodefaultlib", getVSToolchainBinLocation(), outputFilename); cmdline += strprintf(" /machine:AMD64"); for(const auto& i : inputObjects) cmdline += strprintf(" %s", i); if(!frontend::getIsFreestanding() && !frontend::getIsNoStandardLibraries()) { // these dumb paths have spaces in them, so we need to quote it. // link.exe handles its own de-quoting, not cmd.exe or whatever shell. auto sdkRoot = strprintf("\"%s\"", getWindowsSDKLocation()); auto vsLibRoot = strprintf("\"%s\"", getVSToolchainLibLocation()); std::vector umLibs = { "kernel32.lib" }; std::vector ucrtLibs = { "libucrt.lib" }; std::vector msvcLibs = { "libcmt.lib", "libvcruntime.lib", "legacy_stdio_definitions.lib", "legacy_stdio_wide_specifiers.lib" }; for(const auto& l : umLibs) cmdline += strprintf(" %s\\um\\x64\\%s", sdkRoot, l); for(const auto& l : ucrtLibs) cmdline += strprintf(" %s\\ucrt\\x64\\%s", sdkRoot, l); for(const auto& l : msvcLibs) cmdline += strprintf(" %s\\x64\\%s", vsLibRoot, l); } #else // cc -o cmdline = strprintf("cc -o %s", outputFilename); for(const auto& i : inputObjects) cmdline += strprintf(" %s", i); for(const auto& p : frontend::getLibrarySearchPaths()) cmdline += strprintf(" -L%s", p); for(const auto& p : frontend::getFrameworkSearchPaths()) cmdline += strprintf(" -F%s", p); for(const auto& l : frontend::getLibrariesToLink()) cmdline += strprintf(" -l%s", l); for(const auto& f : frontend::getFrameworksToLink()) cmdline += strprintf(" -framework %s", f); if(!frontend::getIsFreestanding() && !frontend::getIsNoStandardLibraries()) cmdline += strprintf(" -lm -lc"); #endif return cmdline; } void addLibrarySearchPaths() { auto libPaths = frontend::getLibrarySearchPaths(); auto frameworkPaths = frontend::getFrameworkSearchPaths(); #if OS_WINDOWS for(const auto& path : libPaths) { if(path.empty()) continue; auto wpath = convertStringToWChar(path); auto cookie = AddDllDirectory(wpath.c_str()); if(cookie) loadedDllDirs.push_back(cookie); } #else auto env = getEnvironmentVar("LD_LIBRARY_PATH"); for(auto L : libPaths) env += strprintf(":%s", L); pushEnvironmentVar("LD_LIBRARY_PATH", env); #if OS_DARWIN { auto env = getEnvironmentVar("DYLD_FRAMEWORK_PATH"); for(auto L : frameworkPaths) env += strprintf(":%s", L); pushEnvironmentVar("DYLD_FRAMEWORK_PATH", env); } #endif #endif } void restoreLibrarySearchPaths() { #if OS_WINDOWS for(auto cookie : loadedDllDirs) RemoveDllDirectory(cookie); #else popEnvironmentVar("LD_LIBRARY_PATH"); #if OS_DARWIN popEnvironmentVar("DYLD_FRAMEWORK_PATH"); #endif #endif } std::vector getDefaultSharedLibraries() { if(frontend::getIsFreestanding() || frontend::getIsNoStandardLibraries()) return { }; #if OS_WINDOWS //? the name is "vcruntime140.dll", which is apparently specific to MSVC 14.0+, apparently 140 is the only number that //? appears to be referenced in online sources. return { "ucrtbase.dll", "vcruntime140.dll" }; #elif OS_DARWIN return { "libc.dylib", "libm.dylib" }; #elif OS_UNIX // note: we do not (and cannot) link libc and libm explicitly under linux. // not sure about other unices. return { }; #endif } std::string getSharedLibraryName(const std::string& name) { #if OS_WINDOWS return strprintf("%s.dll", name); #elif OS_DARWIN return strprintf("lib%s.dylib", name); #elif OS_UNIX return strprintf("lib%s.so", name); #endif } std::string getExecutableName(const std::string& name) { #if OS_WINDOWS return strprintf("%s.exe", name); #else return name; #endif } std::string getObjectFileName(const std::string& name) { #if OS_WINDOWS return strprintf("%s.obj", name); #else return strprintf("%s.o", name); #endif } void performSelfDlOpen() { #if OS_WINDOWS currentModule = GetModuleHandle(nullptr); otherModules.push_back(LoadLibrary("ucrtbase.dll")); otherModules.push_back(LoadLibrary("vcruntime140.dll")); #else currentModule = dlopen(nullptr, RTLD_LAZY); #endif } void performSelfDlClose() { #if OS_WINDOWS for(auto mod : otherModules) FreeLibrary(mod); #endif } void* getSymbol(const std::string& name) { if(!currentModule) error("backend: failed to load current module!"); void* ret = 0; #if OS_WINDOWS ret = GetProcAddress(currentModule, name.c_str()); for(size_t i = 0; !ret && i < otherModules.size(); i++) ret = GetProcAddress(otherModules[i], name.c_str()); #else ret = dlsym(currentModule, name.c_str()); #endif return ret; } } } ================================================ FILE: source/platform/msvcfinder.cpp ================================================ // msvcfinder.cpp // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. #include "defs.h" #include "errors.h" #include "frontend.h" #include #include #if OS_WINDOWS #ifndef NOMINMAX #define NOMINMAX #endif #include namespace platform { namespace compiler { // the techniques used here are with reference to Jon Blow's "microsoft_craziness.h" file. // it was released under the MIT license. see: https://gist.github.com/machinamentum/a2b587a68a49094257da0c39a6c4405f struct DECLSPEC_UUID("B41463C3-8866-43B5-BC33-2B0676F7F42E") DECLSPEC_NOVTABLE ISetupInstance : public IUnknown { STDMETHOD(GetInstanceId)(_Out_ BSTR* pbstrInstanceId) = 0; STDMETHOD(GetInstallDate)(_Out_ LPFILETIME pInstallDate) = 0; STDMETHOD(GetInstallationName)(_Out_ BSTR* pbstrInstallationName) = 0; STDMETHOD(GetInstallationPath)(_Out_ BSTR* pbstrInstallationPath) = 0; STDMETHOD(GetInstallationVersion)(_Out_ BSTR* pbstrInstallationVersion) = 0; STDMETHOD(GetDisplayName)(_In_ LCID lcid, _Out_ BSTR* pbstrDisplayName) = 0; STDMETHOD(GetDescription)(_In_ LCID lcid, _Out_ BSTR* pbstrDescription) = 0; STDMETHOD(ResolvePath)(_In_opt_z_ LPCOLESTR pwszRelativePath, _Out_ BSTR* pbstrAbsolutePath) = 0; }; struct DECLSPEC_UUID("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848") DECLSPEC_NOVTABLE IEnumSetupInstances : public IUnknown { STDMETHOD(Next)(_In_ ULONG celt, _Out_writes_to_(celt, *pceltFetched) ISetupInstance** rgelt, _Out_opt_ _Deref_out_range_(0, celt) ULONG* pceltFetched) = 0; STDMETHOD(Skip)(_In_ ULONG celt) = 0; STDMETHOD(Reset)(void) = 0; STDMETHOD(Clone)(_Deref_out_opt_ IEnumSetupInstances** ppenum) = 0; }; struct DECLSPEC_UUID("42843719-DB4C-46C2-8E7C-64F1816EFD5B") DECLSPEC_NOVTABLE ISetupConfiguration : public IUnknown { STDMETHOD(EnumInstances)(_Out_ IEnumSetupInstances** ppEnumInstances) = 0; STDMETHOD(GetInstanceForCurrentProcess)(_Out_ ISetupInstance** ppInstance) = 0; STDMETHOD(GetInstanceForPath)(_In_z_ LPCWSTR wzPath, _Out_ ISetupInstance** ppInstance) = 0; }; struct DECLSPEC_UUID("42B21B78-6192-463E-87BF-D577838F1D5C") DECLSPEC_NOVTABLE ISetupHelper : public IUnknown { STDMETHOD(ParseVersion)(_In_ LPCOLESTR pwszVersion, _Out_ PULONGLONG pullVersion) = 0; STDMETHOD(ParseVersionRange)(_In_ LPCOLESTR pwszVersionRange, _Out_ PULONGLONG pullMinVersion, _Out_ PULONGLONG pullMaxVersion) = 0; }; struct VersionData { int32_t bestVersion[4]; std::wstring bestName; }; struct FindResult { int windowsVersion; std::string windowsSDKRoot; std::string vsBinDirectory; std::string vsLibDirectory; }; static bool checkFileExists(const std::wstring& name) { auto attrib = GetFileAttributesW(name.c_str()); return attrib != INVALID_FILE_ATTRIBUTES; } static bool visitFiles(const std::wstring& dir, VersionData* vd, std::function visitor) { auto wildcard = dir + L"\\*"; WIN32_FIND_DATAW findData; auto handle = FindFirstFileW(wildcard.c_str(), &findData); if(handle == INVALID_HANDLE_VALUE) return false; while(true) { // make sure it's a directory, and don't read '.' or '..' if((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (findData.cFileName[0] != '.')) { auto full = dir + L"\\" + findData.cFileName; visitor(findData.cFileName, full, vd); } auto success = FindNextFileW(handle, &findData); if(!success) break; } FindClose(handle); return true; } static std::wstring readRegistryString(HKEY key, const std::wstring& name) { // If the registry data changes between the first and second calls to RegQueryValueExW, // we may fail to get the entire key, even though it told us initially that our buffer length // would be big enough. The only solution is to keep looping until we don't fail. DWORD required = 0; auto rc = RegQueryValueExW(key, name.c_str(), NULL, NULL, NULL, &required); if(rc != 0) return L""; wchar_t* value = 0; DWORD length = 0; while(true) { length = required + 2; value = (wchar_t*) malloc(length + 2); if(!value) return L""; DWORD type; rc = RegQueryValueExW(key, name.c_str(), NULL, &type, (LPBYTE) value, &length); if(rc == ERROR_MORE_DATA) { free(value); required = length; continue; } // only get strings if((rc != 0) || (type != REG_SZ)) { free(value); return L""; } break; } auto num_wchars = length / 2; value[num_wchars] = 0; auto ret = std::wstring(value); free(value); return ret; } static void getBestWin10Version(const std::wstring& shortName, const std::wstring& fullName, VersionData* vd) { // find the win10 subdir with the highest version number. int i0 = 0; int i1 = 0; int i2 = 0; int i3 = 0; auto gots = swscanf_s(shortName.c_str(), L"%d.%d.%d.%d", &i0, &i1, &i2, &i3); if(gots < 4) return; auto b0 = vd->bestVersion[0]; auto b1 = vd->bestVersion[1]; auto b2 = vd->bestVersion[2]; auto b3 = vd->bestVersion[3]; // short-circuiting ftw. if((b0 > i0) || (b1 > i1) || (b2 > i2) || (b3 > i3)) return; vd->bestName = fullName; vd->bestVersion[0] = i0; vd->bestVersion[1] = i1; vd->bestVersion[2] = i2; vd->bestVersion[3] = i3; } static void getBestWin8Version(const std::wstring& shortName, const std::wstring& fullName, VersionData* vd) { // find the win8 subdir with the highest version number. int i0 = 0; int i1 = 0; auto gots = swscanf_s(shortName.c_str(), L"winv%d.%d", &i0, &i1); if(gots < 2) return; auto b0 = vd->bestVersion[0]; auto b1 = vd->bestVersion[1]; // short-circuiting ftw. if((b0 > i0) || (b1 > i1)) return; vd->bestName = fullName; vd->bestVersion[0] = i0; vd->bestVersion[1] = i1; } static void findWindowsKitRoot(FindResult* result) { HKEY key; auto rc = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY | KEY_ENUMERATE_SUB_KEYS, &key); if(rc != S_OK) return; defer(RegCloseKey(key)); // find a windows 10 thing auto win10root = readRegistryString(key, L"KitsRoot10"); if(!win10root.empty()) { auto win10lib = win10root + L"Lib"; VersionData vd; memset(&vd, 0, sizeof(VersionData)); visitFiles(win10lib, &vd, &getBestWin10Version); if(!vd.bestName.empty()) { result->windowsVersion = 10; result->windowsSDKRoot = convertWCharToString(vd.bestName); return; } } auto win8root = readRegistryString(key, L"KitsRoot81"); if(!win8root.empty()) { auto win10lib = win10root + L"Lib"; VersionData vd; memset(&vd, 0, sizeof(VersionData)); visitFiles(win10lib, &vd, &getBestWin8Version); if(!vd.bestName.empty()) { result->windowsVersion = 8; result->windowsSDKRoot = convertWCharToString(vd.bestName); return; } } } static std::string trim(std::string s) { auto ltrim = [](std::string& s) -> std::string& { s.erase(0, s.find_first_not_of(" \t\n\r\f\v")); return s; }; auto rtrim = [](std::string& s) -> std::string& { s.erase(s.find_last_not_of(" \t\n\r\f\v") + 1); return s; }; return ltrim(rtrim(s)); } static bool findVSToolchain(FindResult* result) { // for vs >= 2017, we need to do some COM stupidity. CoInitializeEx(NULL, COINIT_MULTITHREADED); GUID my_uid = { 0x42843719, 0xDB4C, 0x46C2, { 0x8E, 0x7C, 0x64, 0xF1, 0x81, 0x6E, 0xFD, 0x5B } }; GUID clsid_setupConfig = { 0x177F0C4A, 0x1CD3, 0x4DE7, { 0xA3, 0x2C, 0x71, 0xDB, 0xBB, 0x9F, 0xA3, 0x6D } }; ISetupConfiguration* config = NULL; auto hr = CoCreateInstance(clsid_setupConfig, NULL, CLSCTX_INPROC_SERVER, my_uid, (void**) &config); if(hr != S_OK) return false; defer(config->Release()); IEnumSetupInstances* instances = NULL; hr = config->EnumInstances(&instances); if(hr != S_OK) return false; if(!instances) return false; defer(instances->Release()); ISetupInstance* inst = 0; uint64_t newestVersionNum = 0; // we look for the newest version that's installed, as opposed to the first. while(true) { ISetupInstance* instance = NULL; auto hr = instances->Next(1, &instance, NULL); if(hr != S_OK) break; BSTR versionString; uint64_t versionNum = 0; hr = instance->GetInstallationVersion(&versionString); if(hr != S_OK) continue; defer(SysFreeString(versionString)); hr = ((ISetupHelper*) config)->ParseVersion(versionString, &versionNum); if(hr != S_OK) continue; if(newestVersionNum == 0 || versionNum > newestVersionNum) { inst = instance; newestVersionNum = versionNum; } else { instance->Release(); } } if(!inst) return false; std::string vsRoot; { BSTR tmp; auto hr = inst->ResolvePath(L"VC", &tmp); if(hr != S_OK) return false; vsRoot = convertWCharToString(std::wstring(tmp)); SysFreeString(tmp); inst->Release(); } std::string toolchainVersion; { auto path = strprintf("%s\\Auxiliary\\Build\\Microsoft.VCToolsVersion.default.txt", vsRoot); auto in = std::ifstream(path, std::ios::in); std::getline(in, toolchainVersion); toolchainVersion = trim(toolchainVersion); } std::string toolchainPath = strprintf("%s\\Tools\\MSVC\\%s", vsRoot, toolchainVersion); if(checkFileExists(convertStringToWChar(toolchainPath))) { //* this is *HOST* architecture, so we can just use our defines. result->vsBinDirectory = strprintf("%s\\bin\\Host%s", toolchainPath, ARCH_64 ? "x64" : "x86"); result->vsLibDirectory = strprintf("%s\\lib", toolchainPath); return true; } else { return false; } } static FindResult* getResult() { static bool cached = false; static FindResult cachedResult; if(!cached) { memset(&cachedResult, 0, sizeof(FindResult)); findWindowsKitRoot(&cachedResult); auto found = findVSToolchain(&cachedResult); if(!found) error("backend: failed to find installed Visual Studio location!"); cached = true; } return &cachedResult; } std::string getWindowsSDKLocation() { return getResult()->windowsSDKRoot; } std::string getVSToolchainLibLocation() { return getResult()->vsLibDirectory; } std::string getVSToolchainBinLocation() { return getResult()->vsBinDirectory; } } } #endif ================================================ FILE: source/platform/platform.cpp ================================================ // platform.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include #include #include "errors.h" #include "frontend.h" #include "platform.h" #if OS_WINDOWS #define WIN32_LEAN_AND_MEAN 1 #ifndef NOMINMAX #define NOMINMAX #endif #include #define USE_MMAP false #else #include #include #include #include #include #define USE_MMAP true #ifdef __MACH__ #include #define EXTRA_MMAP_FLAGS VM_FLAGS_SUPERPAGE_SIZE_2MB #elif defined(MAP_HUGE_2MB) #define EXTRA_MMAP_FLAGS MAP_HUGE_2MB #else #define EXTRA_MMAP_FLAGS 0 #endif #endif namespace platform { #if OS_WINDOWS filehandle_t InvalidFileHandle = INVALID_HANDLE_VALUE; #else filehandle_t InvalidFileHandle = -1; #endif static util::hash_map> environmentStack; std::string getEnvironmentVar(const std::string& name) { #if OS_WINDOWS char buffer[256] = { 0 }; size_t len = 0; if(getenv_s(&len, buffer, name.c_str()) != 0) return ""; else return std::string(buffer, len); #else if(char* val = getenv(name.c_str()); val) return std::string(val); else return ""; #endif } void pushEnvironmentVar(const std::string& name, const std::string& value) { environmentStack[name].push_back(value); #if OS_WINDOWS _putenv_s(name.c_str(), value.c_str()); #else setenv(name.c_str(), value.c_str(), /* overwrite: */ 1); #endif } void popEnvironmentVar(const std::string& name) { auto it = environmentStack.find(name); if(it == environmentStack.end() || it->second.empty()) error("did not push '%s'", name.c_str()); it->second.pop_back(); auto restore = it->second.empty() ? "" : it->second.back(); #if OS_WINDOWS _putenv_s(name.c_str(), restore.c_str()); #else setenv(name.c_str(), restore.c_str(), /* overwrite: */ 1); #endif } #if OS_WINDOWS std::wstring convertStringToWChar(const std::string& s) { if(s.empty()) return L""; if(s.size() > INT_MAX) error("string length %d is too large", s.size()); int required = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), (int) s.size(), NULL, 0); if(required == 0) error("failed to convert string"); auto buf = (LPWSTR) malloc(sizeof(WCHAR) * (required + 1)); if(!buf) error("failed to allocate buffer"); auto ret = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), (int) s.size(), buf, required); iceAssert(ret > 0); auto wstr = std::wstring(buf, ret); free(buf); return wstr; } std::string convertWCharToString(const std::wstring& s) { if(s.empty()) return ""; if(s.size() > INT_MAX) error("string length %d is too large", s.size()); int required = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s.c_str(), -1, NULL, 0, NULL, NULL); if(required == 0) error("failed to convert wstring"); auto buf = (char*) malloc(sizeof(char) * (required + 1)); if(!buf) error("failed to allocate buffer"); auto ret = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s.c_str(), -1, buf, required, NULL, NULL); iceAssert(ret > 0); auto str = std::string(buf, ret - 1); free(buf); return str; } #endif size_t getFileSize(const std::string& path) { #if OS_WINDOWS // note: jesus christ this thing is horrendous HANDLE hd = CreateFile((LPCSTR) path.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if(hd == INVALID_HANDLE_VALUE) error("failed to get filesize for '%s' (error code %d)", path, GetLastError()); // ok, presumably it exists. so, get the size LARGE_INTEGER sz; bool success = GetFileSizeEx(hd, &sz); if(!success) error("failed to get filesize for '%s' (error code %d)", path, GetLastError()); CloseHandle(hd); return (size_t) sz.QuadPart; #else struct stat st; if(stat(path.c_str(), &st) != 0) error("failed to get filesize for '%s' (error code %d / %s)", path, errno, strerror(errno)); return st.st_size; #endif } static util::hash_map cachedFileContents; void cachePreExistingFile(const std::string& path, const std::string& contents) { cachedFileContents[path] = contents; // this will give cache a new id for us. (over there) frontend::cachePreExistingFilename(path); } std::string_view readEntireFile(const std::string& path) { if(auto it = cachedFileContents.find(path); it != cachedFileContents.end()) return it->second; // first, get the size of the file size_t fileLength = getFileSize(path); auto fd = openFile(path.c_str(), O_RDONLY, 0); if(fd == platform::InvalidFileHandle) { perror("there was an error getting opening the file"); exit(-1); } // check if we should mmap // explanation: if we have EXTRA_MMAP_FLAGS, then we're getting 2MB pages -- in which case we should probably only do it // if we have at least 4mb worth of file. // if not, then just 2 * pagesize. #define MINIMUM_MMAP_THRESHOLD (static_cast(((EXTRA_MMAP_FLAGS) != 0) ? (2 * 2 * 1024 * 1024) : 2 * getpagesize())) std::string_view contents; // here's the thing -- we use USE_MMAP at *compile-time*, because on windows some of the constants we're going to use // here aren't available at all if we include it, then it'll be parsed and everything and error out. So, we #ifdef it away. // Problem is, there's another scenario in which we won't want to use mmap -- when the file size is too small. so, that's why the stuff // below is structured the way it is. #if USE_MMAP { if(fileLength >= MINIMUM_MMAP_THRESHOLD) { // ok, do an mmap const char* buf = static_cast(mmap(0, fileLength, PROT_READ, MAP_PRIVATE | EXTRA_MMAP_FLAGS, fd, 0)); if(buf == reinterpret_cast(-1)) { perror("there was an error reading the file"); exit(-1); } contents = std::string_view(buf, fileLength); } } #endif if(contents.empty()) { // read normally //! MEMORY LEAK auto buf = new char[fileLength + 1]; size_t didRead = platform::readFile(fd, buf, fileLength); if(didRead != fileLength) { perror("there was an error reading the file"); error("expected %d bytes, but read only %d", fileLength, didRead); } contents = std::string_view(buf, fileLength); } closeFile(fd); cachedFileContents[path] = contents; return cachedFileContents[path]; } filehandle_t openFile(const char* name, int mode, int flags) { #if OS_WINDOWS bool writing = (mode & O_WRONLY) || (mode & O_RDWR); bool create = (mode & O_CREAT); HANDLE hd = CreateFile((LPCSTR) name, GENERIC_READ | (writing ? GENERIC_WRITE : 0), FILE_SHARE_READ, 0, create ? CREATE_ALWAYS : OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if(hd == INVALID_HANDLE_VALUE) return platform::InvalidFileHandle; return hd; #else return open(name, mode, flags); #endif } void closeFile(filehandle_t fd) { #if OS_WINDOWS CloseHandle(fd); #else close(fd); #endif } void deleteFile(filehandle_t fd) { } size_t readFile(filehandle_t fd, void* buf, size_t count) { #if OS_WINDOWS DWORD didRead = 0; bool success = ReadFile(fd, buf, (DWORD) count, &didRead, 0); if(!success) error("failed to read file (wanted %d bytes, read %d bytes); (error code %d)", count, didRead, GetLastError()); return (size_t) didRead; #else return read(fd, buf, count); #endif } size_t writeFile(filehandle_t fd, void* buf, size_t count) { #if OS_WINDOWS DWORD didWrite = 0; bool success = WriteFile(fd, buf, (DWORD) count, &didWrite, 0); if(!success) error("failed to write file (wanted %d bytes, wrote %d bytes); (error code %d)", count, didWrite, GetLastError()); return (size_t) didWrite; #else return write(fd, buf, count); #endif } bool checkFileExists(const std::string& path) { #if OS_WINDOWS TCHAR* p = (TCHAR*) path.c_str(); DWORD dwAttrib = GetFileAttributes(p); return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); #else struct stat st; return stat(path.c_str(), &st) == 0; #endif } std::string getFullPath(const std::string& partial) { #if OS_WINDOWS { // auto checkFileExists = [](const TCHAR* szPath) -> bool { // DWORD dwAttrib = GetFileAttributes(szPath); // return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); // }; std::string p = partial; std::replace(p.begin(), p.end(), '/', '\\'); HANDLE hd = CreateFile((LPCSTR) p.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if(hd == INVALID_HANDLE_VALUE) return ""; // ok, presumably it exists. defer(CloseHandle(hd)); TCHAR* out = new TCHAR[MAX_PATH]; defer(delete[] out); auto ret = GetFinalPathNameByHandleA(hd, out, MAX_PATH, VOLUME_NAME_DOS); if(ret != 0) { auto str = std::string(out); return str; } else { return ""; } } #else { auto ret = realpath(partial.c_str(), 0); if(ret == 0) return ""; auto str = std::string(ret); free(ret); return str; } #endif } #ifdef _MSC_VER #else #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" #endif size_t getTerminalWidth() { #if OS_WINDOWS { CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); return csbi.srWindow.Right - csbi.srWindow.Left + 1; } #else { struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); return w.ws_col; } #endif } void setupTerminalIfNecessary() { #if OS_WINDOWS // first, enable ansi colours std::vector handles = { STD_OUTPUT_HANDLE, STD_ERROR_HANDLE }; for(auto x : handles) { auto h = GetStdHandle(x); SetConsoleMode(h, ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING); } // then, change the codepage to utf-8: SetConsoleCP(CP_UTF8); #else #endif } void setupCrashHandlers() { #if OS_WINDOWS #else signal(SIGSEGV, [](int) -> void { constexpr const char* msg = COLOUR_RED_BOLD "\n\ncompiler crash! " COLOUR_RESET "(segmentation fault)\n" COLOUR_BLUE_BOLD "stacktrace:\n" COLOUR_RESET; write(1, msg, strlen(msg)); // note: this does not care about being re-entrant in signal handlers. // fuck that noise. printStackTrace(); abort(); }); #endif } #ifdef _MSC_VER #else #pragma GCC diagnostic pop #endif } ================================================ FILE: source/repl/commands.cpp ================================================ // commands.cpp // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. #include #include "defs.h" #include "repl.h" #include "ztmu.h" #include "sst.h" #include "ir/type.h" namespace repl { static void print_help(); static void print_type(const std::string& expr); bool runCommand(const std::string& s, ztmu::State* consoleState) { if(s == "q") { repl::log("exiting repl"); return true; } else if(s == "reset") { repl::setupEnvironment(); repl::log("environment reset"); } else if(s == "help" || s == "?") { print_help(); } else if(s.find("t ") == 0) { print_type(s.substr(2)); } else if(s.find("clear_history") == 0) { // just loading an empty history will effectively clear the history. consoleState->loadHistory({ }); } else { repl::error("invalid command '%s'", s); } return false; } static void print_type(const std::string& line) { bool needmore = false; auto stmt = repl::parseAndTypecheck(line, &needmore); if(needmore) { repl::error("':t' does not support continuations"); } else if(!stmt) { repl::error("invalid expression"); } else if(auto expr = dcast(sst::Expr, *stmt)) { zpr::println("%s%s%s: %s", COLOUR_GREY_BOLD, line, COLOUR_RESET, expr->type); } else { repl::error("'%s' is not an expression", (*stmt)->readableName); } } static std::vector helpLines = { zpr::sprint(""), zpr::sprint("%s*%s overview %s*%s", COLOUR_GREEN_BOLD, COLOUR_RESET, COLOUR_GREEN_BOLD, COLOUR_RESET), zpr::sprint("\u203e\u203e\u203e\u203e\u203e\u203e\u203e\u203e\u203e\u203e\u203e\u203e"), zpr::sprint("The repl accepts Flax expressions and statements; press enter to evaluate the currently entered" " input. If the input was incomplete (eg. ending with a '{'), then the repl will enter a multi-line continuation" " mode. In either case, use the standard keybindings (arrow keys, home/end, etc.) to navigate."), zpr::sprint(""), zpr::sprint("Any definitions (eg. variables, functions) will be treated as if they were declared at global" " scope, while expressions and statements (eg. loops, arithmetic) will be treated as if they were" " written in a function body."), zpr::sprint(""), zpr::sprint("Expressions with values (eg. 3 + 1) will be given monotonic identifiers (eg. %s_0%s, %s_1%s) that" " can be used like any other identifier in code.", COLOUR_BLUE, COLOUR_RESET, COLOUR_BLUE, COLOUR_RESET), zpr::sprint(""), zpr::sprint("Commands begin with ':', and modify the state of the repl or perform other meta-actions."), zpr::sprint(""), zpr::sprint("%s*%s commands %s*%s", COLOUR_GREEN_BOLD, COLOUR_RESET, COLOUR_GREEN_BOLD, COLOUR_RESET), zpr::sprint("\u203e\u203e\u203e\u203e\u203e\u203e\u203e\u203e\u203e\u203e\u203e\u203e"), zpr::sprint(" :? / :help - display help (this listing)"), zpr::sprint(" :q - quit the repl"), zpr::sprint(" :reset - reset the environment, discarding all existing definitions"), zpr::sprint(" :clear_history - clear the history of things"), zpr::sprint(" :t - display the type of an expression"), }; static void print_help() { auto xs = ztmu::prettyFormatTextBlock(helpLines, " ", " "); for(const auto& x : xs) zpr::println(x); } } ================================================ FILE: source/repl/driver.cpp ================================================ // driver.cpp // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. #include #include "repl.h" #include "frontend.h" #define ZTMU_CREATE_IMPL 1 #include "ztmu.h" namespace repl { static constexpr const char* PROMPT_STRING = COLOUR_BLUE_BOLD " * " COLOUR_GREY_BOLD ">" COLOUR_RESET " "; static constexpr const char* WRAP_PROMPT_STRING = COLOUR_GREY_BOLD " |" COLOUR_RESET " "; static constexpr const char* CONT_PROMPT_STRING = COLOUR_YELLOW_BOLD ".. " COLOUR_GREY_BOLD ">" COLOUR_RESET " "; static constexpr const char* EXTRA_INDENT = " "; static constexpr size_t EXTRA_INDENT_LEN = std::char_traits::length(EXTRA_INDENT); void start() { zpr::println("flax repl -- version %s", frontend::getVersion()); zpr::println("type %s:?%s for help\n", COLOUR_GREEN_BOLD, COLOUR_RESET); repl::setupEnvironment(); auto st = ztmu::State(); st.setPrompt(PROMPT_STRING); st.setContPrompt(CONT_PROMPT_STRING); st.setWrappedPrompt(WRAP_PROMPT_STRING); st.setMessageOnControlC(zpr::sprint("%s(use %s:q%s to quit)%s", COLOUR_GREY_BOLD, COLOUR_GREEN, COLOUR_GREY_BOLD, COLOUR_RESET)); // temporary. st.enableExitOnEmptyControlC(); // load the history. st.loadHistory(repl::loadHistory()); // setup the console (on windows, this changes to utf8 codepage.) st.setupConsole(); // we need to put this up here, so the handler can capture it. int indentLevel = 0; st.setKeyHandler(static_cast('}'), [&indentLevel](ztmu::State* st, ztmu::Key k) -> ztmu::HandlerAction { // a bit dirty, but we just do this -- if we can find the indent at the back, then remove it. auto line = st->getCurrentLine(); if(indentLevel > 0 && line.size() >= 2 && line.find(EXTRA_INDENT, line.size() - EXTRA_INDENT_LEN) != -1) { st->setCurrentLine(line.substr(0, line.size() - 2)); indentLevel--; } return ztmu::HandlerAction::CONTINUE; }); while(auto line = st.read()) { auto input = std::string(*line); if(input.empty()) continue; // commands start with ':', but also allow '::' path-prefix. if(input[0] == ':' && input.find("::") != 0) { auto quit = repl::runCommand(input.substr(1), &st); if(quit) break; } else if(bool needmore = repl::processLine(input); needmore) { size_t last_indented_line = 0; auto calc_indent = [&last_indented_line, &st](char c) -> int { // note: we use +1 so that last_indented_line is 1-indexed. this // entire thing is so we don't get increasing indentation levels if // we delete and re-enter on a brace. if(last_indented_line == 0 || st.lineIdx + 1 > last_indented_line) { switch(c) { case '{': [[fallthrough]]; case '(': [[fallthrough]]; case '[': [[fallthrough]]; case ',': { last_indented_line = st.lineIdx + 1; return 1; } } } return 0; }; auto join_lines = [](const std::vector& lines) -> std::string { std::string ret; for(const auto& l : lines) ret += "\n" + l; return ret; }; indentLevel = calc_indent(input.back()); // read more. while(auto lines = st.readContinuation(std::string(indentLevel * EXTRA_INDENT_LEN, ' '))) { auto input = join_lines(*lines); indentLevel += calc_indent(input.back()); needmore = repl::processLine(input); if(!needmore) break; } } st.addPreviousInputToHistory(); // add an extra line printf("\n"); } // save the history. repl::saveHistory(st.getHistory()); // restore the console. st.unsetupConsole(); } } ================================================ FILE: source/repl/execute.cpp ================================================ // execute.cpp // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. #include "repl.h" #include "parser.h" #include "frontend.h" #include "parser_internal.h" #include "codegen.h" #include "typecheck.h" #include "ir/module.h" #include "ir/interp.h" #include "ir/irbuilder.h" #include "memorypool.h" // defined in codegen/directives.cpp fir::ConstantValue* magicallyRunExpressionAtCompileTime(cgn::CodegenState* cs, sst::Stmt* stmt, fir::Type* infer, const fir::Name& fname, fir::interp::InterpState* is = 0); namespace repl { struct State { State() { auto modname = "__repl_mod__"; this->module = new fir::Module(modname); sst::StateTree* tree = new sst::StateTree(modname, 0); this->fs = new sst::TypecheckState(tree); this->cs = new cgn::CodegenState(fir::IRBuilder(this->module)); this->cs->module = this->module; this->interpState = new fir::interp::InterpState(this->module); this->interpState->initialise(/* runGlobalInit: */ true); // so we don't crash, give us a starting location. this->cs->pushLoc(Location()); } ~State() { delete this->interpState; delete this->cs; delete this->fs; delete this->module; } fir::Module* module; cgn::CodegenState* cs; sst::TypecheckState* fs; fir::interp::InterpState* interpState; size_t fnCounter = 0; size_t varCounter = 0; }; static State* state = 0; void setupEnvironment() { if(state) delete state; state = new State(); } void setEnvironment(State* st) { state = st; } State* getEnvironment() { return state; } std::optional parseAndTypecheck(const std::string& line, bool* needmore) { std::string replName = ""; frontend::CollectorState collector; // lex. platform::cachePreExistingFile(replName, line); auto lexResult = frontend::lexTokensFromString(replName, line); // parse, but first setup the environment. auto st = parser::State(lexResult.tokens); auto _stmt = parser::parseStmt(st, /* exprs: */ true); *needmore = false; if(_stmt.needsMoreTokens()) { *needmore = true; return std::nullopt; } else if(_stmt.isError()) { _stmt.err()->post(); return std::nullopt; } else { auto stmt = _stmt.val(); // ugh. auto tcr = TCResult(reinterpret_cast(0)); // there's no need to fiddle with AST-level trees -- once we typecheck it, // it will store the relevant state into the TypecheckState. try { // note: usually, visitDeclarables in the top-level typecheck will set the realScope. // BUT, since we're not doing that, we must set it manually! if(auto def = dcast(ast::Parameterisable, stmt); def) def->enclosingScope = state->fs->scope(); tcr = stmt->typecheck(state->fs); } catch(ErrorException& ee) { ee.err->post(); printf("\n"); return std::nullopt; } if(tcr.isError()) { tcr.error()->post(); printf("\n"); } else if(!tcr.isParametric() && !tcr.isDummy()) { return tcr.stmt(); } return std::nullopt; } } bool processLine(const std::string& line) { // before we begin, bring us into a new namespace. state->fs->pushAnonymousTree(); bool needmore = false; auto stmt = repl::parseAndTypecheck(line, &needmore); if(!stmt) return needmore; { // copy some stuff over. state->cs->typeDefnMap = state->fs->typeDefnMap; // so the thing is, all the previous things have already been code-generated, // and have had their initialisers run. so there's really no need for their // init pieces to stick around. we need to remove the functions as well for this // to work properly! for(auto [ gv, pc ] : state->cs->globalInitPieces) { state->module->removeFunction(pc); delete pc; } state->cs->globalInitPieces.clear(); // ok, we have a thing. try to run it. note: this will help us to run is->initialise(true), // which will call the global inits. this function also calls Stmt::codegen, which will // (potentially) populate the globalInitPieces, before calling cs->finishGlobalInits(). basically, // it's all handled. auto value = magicallyRunExpressionAtCompileTime(state->cs, *stmt, nullptr, fir::Name::obfuscate("__anon_runner_", state->fnCounter++), state->interpState); state->interpState->finalise(); if(value) { // if it was an expression, then give it a name so we can refer to it later. auto init = util::pool(Location(), value->getType()); init->rawValue = CGResult(value); auto vardef = util::pool(Location()); vardef->type = init->type; vardef->id = Identifier(zpr::sprint("_%d", state->varCounter++), IdKind::Name); vardef->global = true; vardef->init = init; state->fs->stree->addDefinition(vardef->id.name, vardef); zpr::println("%s: %s = %s", vardef->id.name, value->getType(), value->str()); } } return false; } } ================================================ FILE: source/repl/history.cpp ================================================ // history.cpp // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. #include #include #include #include "repl.h" #include "platform.h" namespace repl { static std::string getConfigPath() { auto home = platform::getEnvironmentVar("HOME"); // do some checks so we don't try to write stuff into the root directory. return (home + ((home.empty() || home.back() == '/') ? "" : "/")) + ".flax-repl-history"; } void saveHistory(const std::vector>& history) { auto path = getConfigPath(); auto file = std::ofstream(path, std::ios::out | std::ios::binary | std::ios::trunc); if(!file.is_open() || !file.good()) { repl::log("failed to open file to load history (tried '%s')", path); char buf[128] = { 0 }; #if OS_WINDOWS strerror_s(buf, 127, errno); #else strerror_r(errno, buf, 127); #endif repl::log("error was: '%s'", buf); return; } // the format is that each "entry" is NULL-terminated, while each line in each entry is just // newline-terminated. for(const auto& lines : history) { for(const auto& line : lines) { file.write(line.c_str(), line.size()); file.put('\n'); } // write the null-terminator file.put('\0'); } // ok. file.close(); } std::vector> loadHistory() { auto path = getConfigPath(); auto file = std::ifstream(path, std::ios::in | std::ios::binary); if(!file.is_open() || !file.good()) return { }; std::vector> history; while(file.good()) { std::vector current; for(std::string line; std::getline(file, line, '\n'); ) { current.push_back(line); if(file.peek() == '\0') { file.get(); break; } } if(!current.empty()) history.push_back(current); } file.close(); return history; } } ================================================ FILE: source/typecheck/alloc.cpp ================================================ // alloc.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "pts.h" #include "errors.h" #include "typecheck.h" #include "ir/type.h" #include "resolver.h" #include "memorypool.h" TCResult ast::AllocOp::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); fir::Type* elm = fs->convertParserTypeToFIR(this->allocTy); iceAssert(elm); if(this->attrs.has(attr::RAW) && this->counts.size() > 1) error(this, "only one length dimension is supported for raw memory allocation (have %d)", this->counts.size()); std::vector counts = zfu::map(this->counts, [fs](ast::Expr* e) -> auto { auto c = e->typecheck(fs, fir::Type::getNativeWord()).expr(); if(!c->type->isIntegerType()) error(c, "expected integer type ('i64') for alloc count, found '%s' instead", c->type); return c; }); // check for initialiser. if(!elm->isClassType() && !elm->isStructType() && this->args.size() > 0) error(this, "cannot provide arguments to non-struct type '%s'", elm); fir::Type* resType = (this->attrs.has(attr::RAW) || counts.empty() ? (this->isMutable ? elm->getMutablePointerTo() : elm->getPointerTo()) : fir::DynamicArrayType::get(elm)); auto ret = util::pool(this->loc, resType); // ok, check if we're a struct. if((elm->isStructType() || elm->isClassType())) { auto cdf = fs->typeDefnMap[elm]; iceAssert(cdf); auto arguments = sst::resolver::misc::typecheckCallArguments(fs, this->args); auto constructor = sst::resolver::resolveConstructorCall(fs, this->loc, cdf, arguments, PolyArgMapping_t::none()); ret->constructor = constructor.defn(); ret->arguments = arguments; } else if(!this->args.empty()) { if(this->args.size() > 1) error(this, "expected 1 argument in alloc expression for non-struct type '%s' (for value-copy-initialisation), but found %d arguments instead", this->args.size()); auto args = sst::resolver::misc::typecheckCallArguments(fs, this->args); if(args[0].value->type != elm) error(this, "expected argument of type '%s' for value-copy-initialisation in alloc expression, but found '%s' instead", elm, args[0].value->type); // ok loh ret->arguments = args; } if(this->initBody) { iceAssert(!this->attrs.has(attr::RAW) && this->counts.size() > 0); // ok, make a fake vardefn and insert it first. auto fake = util::pool(this->initBody->loc); fake->type = this->allocTy; fake->name = "it"; auto fake2 = util::pool(this->initBody->loc); fake2->type = pts::NamedType::create(this->initBody->loc, INTUNSPEC_TYPE_STRING); fake2->name = "i"; // make a temp scope to enclose it, I guess fs->pushAnonymousTree(); { ret->initBlockVar = dcast(sst::VarDefn, fake->typecheck(fs).defn()); ret->initBlockIdx = dcast(sst::VarDefn, fake2->typecheck(fs).defn()); ret->initBlock = dcast(sst::Block, this->initBody->typecheck(fs).stmt()); iceAssert(ret->initBlockVar && ret->initBlockIdx && ret->initBlock); } fs->popTree(); } ret->elmType = elm; ret->counts = counts; ret->attrs = this->attrs; ret->isMutable = this->isMutable; return TCResult(ret); } TCResult ast::DeallocOp::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); auto ex = this->expr->typecheck(fs).expr(); if(ex->type->isDynamicArrayType()) error(ex, "dynamic arrays are reference-counted, and cannot be manually freed"); else if(!ex->type->isPointerType()) error(ex, "expected pointer or dynamic array type to deallocate; found '%s' instead", ex->type); auto ret = util::pool(this->loc); ret->expr = ex; return TCResult(ret); } ================================================ FILE: source/typecheck/arithmetic.cpp ================================================ // arithmetic.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "errors.h" #include "typecheck.h" #include "ir/type.h" #include "memorypool.h" static sst::FunctionDefn* getOverloadedOperator(sst::TypecheckState* fs, const Location& loc, int kind, std::string op, std::vector args) { auto tree = fs->stree; while(tree) { int best = 10000000; std::vector cands; auto thelist = (kind == 0 ? &tree->infixOperatorOverloads : (kind == 1 ? &tree->prefixOperatorOverloads : &tree->postfixOperatorOverloads)); for(auto ovp : (*thelist)[op]) { int dist = sst::getOverloadDistance(zfu::map(ovp->params, [](const auto& p) { return p.type; }), args); if(dist == -1) continue; if(dist == best) { cands.push_back(ovp); } else if(dist < best) { best = dist; cands.clear(); cands.push_back(ovp); } } if(cands.size() > 0) { if(cands.size() > 1) { auto err = SimpleError::make(loc, "ambiguous use of overloaded operator '%s'", op); for(auto c : cands) err->append(SimpleError::make(MsgType::Note, c->loc, "potential overload candidate here:")); err->postAndQuit(); } else { return cands[0]; } } // only go up if we didn't find anything here. tree = tree->parent; } return 0; } fir::Type* sst::TypecheckState::getBinaryOpResultType(fir::Type* left, fir::Type* right, const std::string& op, sst::FunctionDefn** overloadFn) { if(op == Operator::LogicalOr || op == Operator::LogicalAnd || op == Operator::LogicalNot) { return fir::Type::getBool(); } else if(op == Operator::CompareEQ || op == Operator::CompareNEQ) { if(left == right || fir::getCastDistance(left, right) >= 0 || fir::getCastDistance(right, left) >= 0 || (left->isConstantNumberType() && right->isConstantNumberType())) { return fir::Type::getBool(); } } else if(op == Operator::CompareLT || op == Operator::CompareGT || op == Operator::CompareLEQ || op == Operator::CompareGEQ) { // we handle this separately because we only want to check for number types and string types. bool ty_compat = (left == right || fir::getCastDistance(left, right) >= 0 || fir::getCastDistance(right, left) >= 0 || (left->isConstantNumberType() && right->isConstantNumberType())); bool ty_comparable = (left->isStringType() || left->isArraySliceType() || left->isArrayType() || left->isDynamicArrayType() || left->isPrimitiveType() || left->isEnumType() || left->isConstantNumberType()); if(ty_compat && ty_comparable) { return fir::Type::getBool(); } } else if(op == Operator::TypeIs) { return fir::Type::getBool(); } else if(op == Operator::TypeCast) { if(right->isUnionVariantType()) return right->toUnionVariantType()->getInteriorType(); return right; } else if(op == Operator::Plus) { if(left->isConstantNumberType() && right->isConstantNumberType()) return fir::unifyConstantTypes(left->toConstantNumberType(), right->toConstantNumberType()); else if(left->isPrimitiveType() && right->isPrimitiveType() && left == right) return left; else if(left->isStringType() && (right->isStringType() || right->isCharSliceType() || right->isCharType())) return fir::Type::getString(); else if(left->isDynamicArrayType() && right->isDynamicArrayType() && left == right) return left; else if(left->isDynamicArrayType() && left->getArrayElementType() == right) return left; else if((left->isConstantNumberType() && right->isPrimitiveType()) || (left->isPrimitiveType() && right->isConstantNumberType())) return (left->isConstantNumberType() ? right : left); else if(left->isPointerType() && (right->isIntegerType() || right->isConstantNumberType())) return left; else if(right->isPointerType() && (left->isIntegerType() || left->isConstantNumberType())) return right; } else if(op == Operator::Minus) { if(left->isConstantNumberType() && right->isConstantNumberType()) return fir::unifyConstantTypes(left->toConstantNumberType(), right->toConstantNumberType()); else if(left->isPrimitiveType() && right->isPrimitiveType() && left == right) return left; else if((left->isConstantNumberType() && right->isPrimitiveType()) || (left->isPrimitiveType() && right->isConstantNumberType())) return (left->isConstantNumberType() ? right : left); else if(left->isPointerType() && (right->isIntegerType() || right->isConstantNumberType())) return left; else if(right->isPointerType() && (left->isIntegerType() || left->isConstantNumberType())) return right; } else if(op == Operator::Multiply) { if(left->isConstantNumberType() && right->isConstantNumberType()) return fir::unifyConstantTypes(left->toConstantNumberType(), right->toConstantNumberType()); else if(left->isPrimitiveType() && right->isPrimitiveType() && left == right) return left; else if((left->isConstantNumberType() && right->isPrimitiveType()) || (left->isPrimitiveType() && right->isConstantNumberType())) return (left->isConstantNumberType() ? right : left); } else if(op == Operator::Divide) { if(left->isConstantNumberType() && right->isConstantNumberType()) return fir::unifyConstantTypes(left->toConstantNumberType(), right->toConstantNumberType()); else if(left->isPrimitiveType() && right->isPrimitiveType() && left == right) return left; else if((left->isConstantNumberType() && right->isPrimitiveType()) || (left->isPrimitiveType() && right->isConstantNumberType())) return (left->isConstantNumberType() ? right : left); } else if(op == Operator::Modulo) { if(left->isConstantNumberType() && right->isConstantNumberType()) { return fir::unifyConstantTypes(left->toConstantNumberType(), right->toConstantNumberType()); } else if((left->isIntegerType() && right->isIntegerType()) || (left->isFloatingPointType() && right->isFloatingPointType())) { return (left->getBitWidth() > right->getBitWidth()) ? left : right; } else if((left->isIntegerType() && right->isFloatingPointType()) || (left->isFloatingPointType() && right->isIntegerType())) { return (left->isFloatingPointType() ? left : right); } else if((left->isConstantNumberType() && right->isPrimitiveType()) || (left->isPrimitiveType() && right->isConstantNumberType())) { return (left->isConstantNumberType() ? right : left); } else { return left; } } else if(zfu::match(op, Operator::BitwiseOr, Operator::BitwiseAnd, Operator::BitwiseXor)) { if(left == right) return left; } // ok, check the operator map. { auto oper = getOverloadedOperator(this, this->loc(), 0, op, { left, right }); if(oper) { if(overloadFn) *overloadFn = oper; return oper->returnType; } } return 0; } TCResult ast::BinaryOp::typecheck(sst::TypecheckState* fs, fir::Type* inferred) { fs->pushLoc(this); defer(fs->popLoc()); iceAssert(!Operator::isAssignment(this->op)); auto l = this->left->typecheck(fs, inferred).expr(); sst::Expr* r = 0; //* this checks for the cast like this: `foo as mut` or `foo as !mut` //* the former makes an immutable thing mutable, and the latter vice versa. if(auto mte = dcast(MutabilityTypeExpr, this->right)) { // see what the left side type is. if(l->type->isPointerType()) { if(l->type->isMutablePointer() == mte->mut) warn(this, "redundant cast: type '%s' is already %smutable", l->type, mte->mut ? "" : "im"); if(mte->mut) r = sst::TypeExpr::make(mte->loc, l->type->getMutablePointerVersion()); else r = sst::TypeExpr::make(mte->loc, l->type->getImmutablePointerVersion()); } else if(l->type->isArraySliceType()) { if(l->type->toArraySliceType()->isMutable() == mte->mut) warn(this, "redundant cast: type '%s' is already %smutable", l->type, mte->mut ? "" : "im"); r = sst::TypeExpr::make(mte->loc, fir::ArraySliceType::get(l->type->getArrayElementType(), mte->mut)); } else { error(this, "invalid cast: type '%s' does not distinguish between mutable and immutable variants", l->type); } } else { this->right->checkAsType = (this->op == Operator::TypeCast || this->op == Operator::TypeIs); if(this->right->checkAsType && l->type->isUnionType()) inferred = l->type; r = this->right->typecheck(fs, inferred).expr(); if(this->right->checkAsType) r = util::pool(r->loc, r->type); // final check -- see if we're trying to unwrap to a union variant with no value (ie. a void type!) // note: this is valid if we're just checking 'if' -- but not if we're casting (ie unwrapping!) if(this->op == Operator::TypeCast && l->type->isUnionType() && r->type->isUnionVariantType() && r->type->toUnionVariantType()->getInteriorType()->isVoidType()) { error(this->right, "unwrapping a value (of union type '%s') to the variant '%s' does not yield a value (the variant has no data)", l->type, r->type->toUnionVariantType()->getName()); } } iceAssert(l && r); auto lt = l->type; auto rt = r->type; sst::FunctionDefn* overloadFn = 0; fir::Type* rest = fs->getBinaryOpResultType(lt, rt, this->op, &overloadFn); if(!rest) { SpanError::make(SimpleError::make(this->loc, "unsupported operator '%s' between types '%s' and '%s'", this->op, lt, rt)) ->add(util::ESpan(this->left->loc, strprintf("type '%s'", lt))) ->add(util::ESpan(this->right->loc, strprintf("type '%s'", rt))) ->postAndQuit(); } auto ret = util::pool(this->loc, rest); ret->left = dcast(sst::Expr, l); ret->right = dcast(sst::Expr, r); ret->op = this->op; ret->overloadedOpFunction = overloadFn; return TCResult(ret); } TCResult ast::UnaryOp::typecheck(sst::TypecheckState* fs, fir::Type* inferred) { fs->pushLoc(this); defer(fs->popLoc()); auto v = this->expr->typecheck(fs, inferred).expr(); auto t = v->type; fir::Type* out = 0; // check for custom ops first, i guess. { auto oper = getOverloadedOperator(fs, this->loc, this->isPostfix ? 2 : 1, this->op, { t }); if(oper) { auto ret = util::pool(this->loc, oper->returnType); ret->op = this->op; ret->expr = v; ret->overloadedOpFunction = oper; return TCResult(ret); } } if(this->op == Operator::LogicalNot) { // check if we're convertible to bool if(!t->isBoolType()) error(this, "invalid use of logical-not-operator '!' on non-boolean type '%s'", t); out = fir::Type::getBool(); } else if(this->op == Operator::UnaryPlus || this->op == Operator::UnaryMinus) { if(t->isConstantNumberType()) { out = (op == "-" ? fir::ConstantNumberType::get(t->toConstantNumberType()->isSigned(), t->toConstantNumberType()->isFloating(), t->toConstantNumberType()->getMinBits()) : t); } else if(!t->isIntegerType() && !t->isFloatingPointType()) { error(this, "invalid use of unary plus/minus operator '+'/'-' on non-numerical type '%s'", t); } else if(op == "-" && t->isIntegerType() && !t->isSignedIntType()) { error(this, "invalid use of unary negation operator '-' on unsigned integer type '%s'", t); } out = t; } else if(this->op == Operator::BitwiseNot) { if(t->isConstantNumberType()) error(this, "bitwise operations are not supported on literal numbers"); else if(!t->isIntegerType()) error(this, "invalid use of bitwise not operator '~' on non-integer type '%s'", t); else if(t->isSignedIntType()) error(this, "invalid use of bitwise not operator '~' on signed integer type '%s'", t); out = t; } else if(this->op == Operator::PointerDeref) { if(!t->isPointerType()) error(this, "invalid use of dereference operator '*' on non-pointer type '%s'", t); out = t->getPointerElementType(); } else if(this->op == Operator::AddressOf) { if(t->isFunctionType()) error(this, "cannot take the address of a function; use it as a value type"); out = t->getPointerTo(); } else { error(this, "unsupported unary operator '%s' on type '%s'", this->op, v->type); } auto ret = util::pool(this->loc, out); ret->op = this->op; ret->expr = v; return TCResult(ret); } TCResult ast::ComparisonOp::typecheck(sst::TypecheckState* fs, fir::Type* inferred) { fs->pushLoc(this); defer(fs->popLoc()); iceAssert(this->exprs.size() == this->ops.size() + 1); /* basically, we transform us into a series of chained "&&" binops. eg: 10 < 20 < 30 > 25 > 15 becomes (10 < 20) && (20 < 30) && (30 > 25) && (25 > 15) */ std::vector> bins; // loop till the second last. for(size_t i = 0; i < this->exprs.size() - 1; i++) { auto left = this->exprs[i]; auto right = this->exprs[i + 1]; auto op = this->ops[i]; bins.push_back({ util::pool(op.second, op.first, left, right), op.second }); } iceAssert(bins.size() > 0); // we handle single-comparisons too, so make sure to account for that. if(bins.size() == 1) { return bins[0].first->typecheck(fs, inferred); } else { // make a binop combining everything, left-associatively. iceAssert(bins.size() > 1); BinaryOp* lhs = util::pool(bins[0].second, Operator::LogicalAnd, bins[0].first, bins[1].first); for(size_t i = 2; i < bins.size(); i++) lhs = util::pool(bins[i].second, Operator::LogicalAnd, lhs, bins[i].first); return lhs->typecheck(fs, inferred); } } ================================================ FILE: source/typecheck/assign.cpp ================================================ // assign.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "errors.h" #include "typecheck.h" #include "ir/type.h" #include "ir/constant.h" #include "memorypool.h" TCResult ast::AssignOp::typecheck(sst::TypecheckState* fs, fir::Type* infer) { // check the left side auto l = this->left->typecheck(fs).expr(); auto r = this->right->typecheck(fs, l->type).expr(); if(r->type->isVoidType()) error(this->right, "value has void type"); // check if we can do it first auto lt = l->type; auto rt = r->type; bool skipCheck = false; if(this->op != Operator::Assign) { auto nonass = Operator::getNonAssignmentVersion(this->op); if(fs->getBinaryOpResultType(lt, rt, nonass) == 0) { error(this, "unsupported operator '%s' between types '%s' and '%s', in compound assignment operator '%s'", nonass, lt, rt, this->op); } skipCheck = true; } if(!skipCheck && lt != rt && fir::getCastDistance(rt, lt) < 0) { SpanError::make(SimpleError::make(this->loc, "cannot assign value of type '%s' to expected type '%s'", rt, lt)) ->add(util::ESpan(this->left->loc, strprintf("type '%s'", lt))) ->add(util::ESpan(this->right->loc, strprintf("type '%s'", rt))) ->postAndQuit(); } //* note: check for the special case of assigning to a tuple literal, to allow the (a, b) = (b, a) swapping idiom if(auto tuple = dcast(sst::LiteralTuple, l)) { auto ret = util::pool(this->loc); for(auto v : tuple->values) ret->lefts.push_back(v); ret->right = r; return TCResult(ret); } else { auto ret = util::pool(this->loc); ret->op = this->op; ret->left = l; ret->right = r; return TCResult(ret); } } ================================================ FILE: source/typecheck/call.cpp ================================================ // call.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "sst.h" #include "errors.h" #include "typecheck.h" #include "resolver.h" #include "ir/type.h" #include "memorypool.h" sst::Expr* ast::FunctionCall::typecheckWithArguments(sst::TypecheckState* fs, const std::vector& _arguments, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); if(auto ty = fs->checkIsBuiltinConstructorCall(this->name, _arguments)) { auto ret = util::pool(this->loc, ty); ret->callee = sst::TypeExpr::make(this->loc, ty); ret->arguments = zfu::map(_arguments, [](const auto& e) -> sst::Expr* { return e.value; }); return ret; } // resolve the function call here std::vector ts = _arguments; auto res = sst::resolver::resolveFunctionCall(fs, this->loc, this->name, &ts, this->mappings, this->traverseUpwards, infer); auto target = res.defn(); iceAssert(target); if(auto strdf = dcast(sst::StructDefn, target)) { auto ret = util::pool(this->loc, strdf->type); ret->target = strdf; ret->arguments = ts; return ret; } else if(auto uvd = dcast(sst::UnionVariantDefn, target)) { auto unn = uvd->parentUnion; iceAssert(unn); auto ret = util::pool(this->loc, unn->type); ret->variantId = unn->type->toUnionType()->getIdOfVariant(uvd->variantName); ret->parentUnion = unn; ret->args = ts; return ret; } else { iceAssert(target->type->isFunctionType()); //* note: we check for this->name != "init" because when we explicitly call an init function, we don't want the extra stuff that //* comes with that -- we'll just treat it as a normal function call. if(auto fnd = dcast(sst::FunctionDefn, target); this->name != "init" && fnd && fnd->id.name == "init" && fnd->parentTypeForMethod && fnd->parentTypeForMethod->isClassType()) { // ok, great... I guess? auto ret = util::pool(this->loc, fnd->parentTypeForMethod); ret->target = fnd; ret->arguments = ts; ret->classty = dcast(sst::ClassDefn, fs->typeDefnMap[fnd->parentTypeForMethod]); iceAssert(ret->target); return ret; } auto call = util::pool(this->loc, target->type->toFunctionType()->getReturnType()); call->name = this->name; call->target = target; call->arguments = ts; if(auto fd = dcast(sst::FunctionDefn, target); fd && fd->parentTypeForMethod) { // check if it's a method call // if so, indicate it. here, we set 'isImplicitMethodCall' to true, as an assumption. // in DotOp's typecheck, *after* calling this typecheck(), we set it back to false // so, if it was really an implicit call, it remains set // if it was a dot-op call, it gets set back to false by the dotop checking. call->isImplicitMethodCall = true; } return call; } } sst::Expr* ast::ExprCall::typecheckWithArguments(sst::TypecheckState* fs, const std::vector& arguments, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); auto target = this->callee->typecheck(fs).expr(); iceAssert(target); if(!target->type->isFunctionType()) error(this->callee, "expression with non-function-type '%s' cannot be called", target->type); auto ft = target->type->toFunctionType(); auto [ dist, errs ] = sst::resolver::computeOverloadDistance(this->loc, zfu::map(ft->getArgumentTypes(), [](fir::Type* t) -> auto { return fir::LocatedType(t, Location()); }), zfu::map(arguments, [](const FnCallArgument& fca) -> fir::LocatedType { return fir::LocatedType(fca.value->type, fca.loc); }), target->type->toFunctionType()->isCStyleVarArg(), this->loc); if(errs != nullptr || dist == -1) { auto x = SimpleError::make(this->loc, "mismatched types in call to function pointer"); if(errs) errs->prepend(x); else errs = x; errs->postAndQuit(); } auto ret = util::pool(this->loc, target->type->toFunctionType()->getReturnType()); ret->callee = target; ret->arguments = zfu::map(arguments, [](const auto& e) -> sst::Expr* { return e.value; }); return ret; } TCResult ast::ExprCall::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); return TCResult(this->typecheckWithArguments(fs, sst::resolver::misc::typecheckCallArguments(fs, this->args), infer)); } TCResult ast::FunctionCall::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); return TCResult(this->typecheckWithArguments(fs, sst::resolver::misc::typecheckCallArguments(fs, this->args), infer)); } ================================================ FILE: source/typecheck/classes.cpp ================================================ // classes.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "defs.h" #include "pts.h" #include "errors.h" #include "ir/type.h" #include "resolver.h" #include "typecheck.h" #include "memorypool.h" // defined in typecheck/structs.cpp void checkFieldRecursion(sst::TypecheckState* fs, fir::Type* strty, fir::Type* field, const Location& floc); TCResult ast::ClassDefn::generateDeclaration(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) { fs->pushLoc(this); defer(fs->popLoc()); auto [ success, ret ] = this->checkForExistingDeclaration(fs, gmaps); if(!success) return TCResult::getParametric(); else if(ret) return TCResult(ret); auto defnname = util::typeParamMapToString(this->name, gmaps); auto defn = util::pool(this->loc); defn->bareName = this->name; defn->attrs = this->attrs; defn->id = Identifier(defnname, IdKind::Type); defn->id.scope = this->enclosingScope; defn->visibility = this->visibility; defn->original = this; defn->enclosingScope = this->enclosingScope; defn->innerScope = this->enclosingScope.appending(defnname); // make all our methods be methods for(auto m : this->methods) { m->parentType = this; m->enclosingScope = defn->innerScope; } for(auto m : this->initialisers) { m->parentType = this; m->enclosingScope = defn->innerScope; } for(auto m : this->staticMethods) { m->enclosingScope = defn->innerScope; } auto cls = fir::ClassType::createWithoutBody(defn->id.convertToName()); defn->type = cls; // why do we do this when generating the declaration instead of only when we typecheck? // as it currently stands, this means that our base class + any traits must appear before // this class definition in the source code, which is kinda dumb. for(auto base : zfu::map(this->bases, [fs](auto t) -> auto { return fs->convertParserTypeToFIR(t); })) { if(base->isClassType()) { if(defn->baseClass) error(this, "cannot inherit from more than one class (already inherited from '%s')", defn->baseClass->id.name); else if(!defn->traits.empty()) error(this, "base class must come before any traits in the inheritance list"); auto basedef = dcast(sst::ClassDefn, fs->typeDefnMap[base]); iceAssert(basedef); defn->baseClass = basedef; cls->setBaseClass(base->toClassType()); } else if(base->isTraitType()) { auto tdef = dcast(sst::TraitDefn, fs->typeDefnMap[base]); iceAssert(tdef); defn->traits.push_back(tdef); cls->addTraitImpl(tdef->type->toTraitType()); } else { error(this, "invalid type '%s' in inheritance list of class", base); } } if(auto err = fs->checkForShadowingOrConflictingDefinition(defn, [](auto, auto) -> bool { return true; })) return TCResult(err); // add it first so we can use it in the method bodies, // and make pointers to it { defn->enclosingScope.stree->addDefinition(defnname, defn, gmaps); fs->typeDefnMap[cls] = defn; } fs->teleportInto(defn->innerScope); { for(auto t : this->nestedTypes) { t->enclosingScope = defn->innerScope; t->generateDeclaration(fs, 0, { }); } } fs->teleportOut(); this->genericVersions.push_back({ defn, fs->getGenericContextStack() }); return TCResult(defn); } TCResult ast::ClassDefn::typecheck(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) { fs->pushLoc(this); defer(fs->popLoc()); auto tcr = this->generateDeclaration(fs, infer, gmaps); if(tcr.isParametric()) return tcr; else if(!tcr.isDefn()) error(this, "failed to generate declaration for function '%s'", this->name); auto defn = dcast(sst::ClassDefn, tcr.defn()); iceAssert(defn); if(this->finishedTypechecking.find(defn) != this->finishedTypechecking.end()) return TCResult(defn); auto cls = defn->type->toClassType(); iceAssert(cls); fs->teleportInto(defn->innerScope); if(this->initialisers.empty()) error(this, "class must have at least one initialiser"); for(auto t : this->nestedTypes) { auto tcr = t->typecheck(fs); if(tcr.isParametric()) continue; if(tcr.isError()) error(t, "failed to generate declaration for nested type '%s' in struct '%s'", t->name, this->name); auto st = dcast(sst::TypeDefn, tcr.defn()); iceAssert(st); defn->nestedTypes.push_back(st); } fs->pushSelfContext(cls); { std::vector> tys; for(auto f : this->fields) { auto v = dcast(sst::StructFieldDefn, f->typecheck(fs).defn()); iceAssert(v); defn->fields.push_back(v); tys.push_back({ v->id.name, v->type }); checkFieldRecursion(fs, cls, v->type, v->loc); std::function checkDupe = [](sst::ClassDefn* cls, sst::StructFieldDefn* fld) -> auto { while(cls) { for(auto bf : cls->fields) { if(bf->id.name == fld->id.name) { SimpleError::make(fld->loc, "redefinition of field '%s' (with type '%s'), that exists in the base class '%s'", fld->id.name, fld->type, cls->id) ->append(SimpleError::make(MsgType::Note, bf->loc, "'%s' was previously defined in the base class here:", fld->id.name)) ->append(SimpleError::make(MsgType::Note, cls->loc, "base class '%s' was defined here:", cls->id)) ->postAndQuit(); } } cls = cls->baseClass; } }; checkDupe(defn->baseClass, v); } cls->setMembers(tys); { //* check for what would be called 'method hiding' in c++, and also valid overrides. // TODO: make an error note about co/contra-variance for param/return types. right now it just complains and it's vague af. auto checkAgainstBaseClasses = [](sst::ClassDefn* cls, sst::FunctionDefn* meth) -> auto { auto checkSingleMethod = [](sst::ClassDefn* cls, sst::FunctionDefn* self, sst::FunctionDefn* bf, bool* matchedName) -> bool { if(bf->id.name == self->id.name) { *matchedName |= true; if(!fir::areMethodsVirtuallyCompatible(bf->type->toFunctionType(), self->type->toFunctionType(), /* trait checking: */ false)) { return false; } // check for virtual functions. //* note: we don't need to care if 'bf' is the base method, because if we are 'isOverride', then we are also //* 'isVirtual'. // nice comprehensive error messages, I hope. if(!self->isOverride) { auto err = SimpleError::make(self->loc, "redefinition of method '%s' (with type '%s'), that exists in" " the base class '%s'", self->id.name, self->type, cls->id); if(bf->isVirtual) { err->append(SimpleError::make(MsgType::Note, bf->loc, "'%s' was defined as a virtual method; to override it, use the 'override' keyword", bf->id.name)); } else { err->append( SimpleError::make(MsgType::Note, bf->loc, "'%s' was previously defined in the base class '%s'" " as a non-virtual method here:", bf->id.name, cls->id.name )->append(BareError::make(MsgType::Note, "to override it, define '%s' as a virtual method", bf->id.name) ) ); } err->postAndQuit(); } else if(!bf->isVirtual) { SimpleError::make(self->loc, "cannot override non-virtual method '%s'", bf->id.name) ->append(SimpleError::make(MsgType::Note, bf->loc, "'%s' was previously defined in the base class '%s' as a non-virtual method here:", bf->id.name, cls->id.name) )->append(BareError::make(MsgType::Note, "to override it, define '%s' as a virtual method", bf->id.name)) ->postAndQuit(); } return true; } return false; }; bool matchedSig = false; bool matchedName = false; while(cls) { for(auto bf : cls->methods) matchedSig |= checkSingleMethod(cls, meth, bf, &matchedName); cls = cls->baseClass; } if(meth->isOverride && !matchedSig) { if(matchedName && !matchedSig) { error(meth, "invalid override: no method named '%s' in any base class with a signature matching" " (or compatible with) '%s'", meth->id.name, meth->type->str()); } else if(!matchedName) { error(meth, "invalid override: no method in any base class named '%s'", meth->id.name); } } }; for(auto m : this->methods) { if(m->name == "init") error(m, "cannot have methods named 'init' in a class; to create an initialiser, omit the 'fn' keyword."); auto res = m->generateDeclaration(fs, cls, { }); if(res.isParametric()) continue; auto decl = dcast(sst::FunctionDefn, res.defn()); iceAssert(decl); defn->methods.push_back(decl); checkAgainstBaseClasses(defn->baseClass, decl); } } { // make the constructors for(auto it : this->initialisers) { auto decl = dcast(sst::FunctionDefn, it->generateDeclaration(fs, cls, { }).defn()); iceAssert(decl); defn->methods.push_back(decl); defn->initialisers.push_back(decl); } // and the destructor if(this->deinitialiser) { auto decl = dcast(sst::FunctionDefn, this->deinitialiser->generateDeclaration(fs, cls, { }).defn()); iceAssert(decl); defn->methods.push_back(decl); defn->deinitialiser = decl; } if(this->copyInitialiser) { auto decl = dcast(sst::FunctionDefn, this->copyInitialiser->generateDeclaration(fs, cls, { }).defn()); iceAssert(decl); defn->methods.push_back(decl); defn->copyInitialiser = decl; } if(this->moveInitialiser) { auto decl = dcast(sst::FunctionDefn, this->moveInitialiser->generateDeclaration(fs, cls, { }).defn()); iceAssert(decl); defn->methods.push_back(decl); defn->moveInitialiser = decl; } } // copy all the things from the superclass into ourselves. if(defn->baseClass) { // basically, the only things we want to import from the base class are fields and methods -- not initialisers. // base-class-constructors must be called using `super(...)` syntax. auto tree = defn->baseClass->innerScope.stree; iceAssert(tree); std::function recursivelyImport = [&](sst::StateTree* from, sst::StateTree* to) -> void { for(auto def : from->getAllDefinitions()) { if(!dcast(sst::ClassInitialiserDefn, def)) to->addDefinition(def->id.name, def); } for(auto sub : from->subtrees) { if(to->subtrees.find(sub.first) == to->subtrees.end()) to->findOrCreateSubtree(sub.first); recursivelyImport(sub.second, to->subtrees[sub.first]); } }; recursivelyImport(tree, fs->stree); } for(auto f : this->staticFields) { auto v = dcast(sst::VarDefn, f->typecheck(fs).defn()); iceAssert(v); defn->staticFields.push_back(v); } for(auto m : this->staticMethods) { // infer is 0 because this is a static thing auto res = m->generateDeclaration(fs, 0, { }); if(res.isParametric()) continue; auto decl = dcast(sst::FunctionDefn, res.defn()); iceAssert(decl); defn->staticMethods.push_back(decl); } // once we get all the proper declarations and such, create the function bodies. if(!cls->containsPlaceholders()) { for(auto m : this->methods) m->typecheck(fs, cls, { }); for(auto m : this->initialisers) m->typecheck(fs, cls, { }); for(auto m : this->staticMethods) m->typecheck(fs, 0, { }); if(this->deinitialiser) this->deinitialiser->typecheck(fs, cls, { }); if(this->copyInitialiser) this->copyInitialiser->typecheck(fs, cls, { }); if(this->moveInitialiser) this->moveInitialiser->typecheck(fs, cls, { }); } } fs->popSelfContext(); fs->teleportOut(); this->finishedTypechecking.insert(defn); return TCResult(defn); } TCResult ast::InitFunctionDefn::typecheck(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) { iceAssert(infer && infer->isClassType()); auto cls = infer->toClassType(); auto ret = dcast(sst::FunctionDefn, this->actualDefn->typecheck(fs, cls, gmaps).defn()); // if the initialiser was polymorphic, then don't generate bodies! if(ret->type->containsPlaceholders()) return TCResult::getParametric(); // only check this stuff for the real constructor. if(this->name == "init") { if(cls->getBaseClass() && !this->didCallSuper) { error(this, "initialiser for class '%s' must explicitly call an initialiser of the base class '%s'", cls->getTypeName().name, cls->getBaseClass()->getTypeName().name); } else if(!cls->getBaseClass() && this->didCallSuper) { error(this, "cannot call base class initialiser for class '%s' when it does not inherit from a base class", cls->getTypeName().name); } else if(cls->getBaseClass() && this->didCallSuper) { auto base = cls->getBaseClass(); auto call = util::pool(this->loc, base); call->classty = dcast(sst::ClassDefn, fs->typeDefnMap[base]); iceAssert(call->classty); std::vector baseargs; { auto restore = fs->stree; fs->stree = ret->insideTree; baseargs = sst::resolver::misc::typecheckCallArguments(fs, this->superArgs); fs->stree = restore; } auto constr = sst::resolver::resolveConstructorCall(fs, this->loc, call->classty, baseargs, PolyArgMapping_t::none()); call->arguments = baseargs; call->target = dcast(sst::FunctionDefn, constr.defn()); iceAssert(call->target); // insert it as the first thing. ret->body->statements.insert(ret->body->statements.begin(), call); } } return TCResult(ret); } TCResult ast::InitFunctionDefn::generateDeclaration(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) { //* so here's the thing //* basically this init function thingy is just a normal function definition //* but due to the way the AST was built, and because it's actually slightly less messy IMO, //* we return a separate AST type that does not inherit from FuncDefn. //* so, to reduce code dupe and make it less stupid, we actually make a fake FuncDefn from ourselves, //* and typecheck that, returning that as the result. //* we don't want to be carrying too many distinct types around in SST nodes. iceAssert(infer); this->actualDefn = util::pool(this->loc); this->actualDefn->name = this->name; this->actualDefn->body = this->body; this->actualDefn->params = this->params; this->actualDefn->parentType = this->parentType; this->actualDefn->returnType = pts::NamedType::create(this->loc, VOID_TYPE_STRING); this->actualDefn->enclosingScope = this->enclosingScope; //* note: constructors will always mutate, definitely. this->actualDefn->isMutating = true; auto ret = this->actualDefn->generateDeclaration(fs, infer, gmaps); if(ret.isDefn()) { auto def = dcast(sst::FunctionDefn, ret.defn()); iceAssert(def); // do some checks. if(this->name == "copy") { if(def->params.size() != 2) { error(def, "copy initialiser must take exactly one argument, %d were found", def->params.size() - 1); } else if(auto ty = def->params[1].type; !ty->isImmutablePointer() || ty->getPointerElementType() != def->parentTypeForMethod) { error(def->params[1].loc, "parameter of copy initialiser must have type '&self' (aka '%s'), found '%s' instead", def->parentTypeForMethod->getPointerTo(), ty); } } else if(this->name == "move") { if(def->params.size() != 2) { error(def, "move initialiser must take exactly one argument, %d were found", def->params.size() - 1); } else if(auto ty = def->params[1].type; !ty->isMutablePointer() || ty->getPointerElementType() != def->parentTypeForMethod) { error(def->params[1].loc, "parameter of move initialiser must have type '&mut self' (aka '%s'), found '%s' instead", def->parentTypeForMethod->getMutablePointerTo(), ty); } } } return ret; } ================================================ FILE: source/typecheck/controlflow.cpp ================================================ // controlflow.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "errors.h" #include "typecheck.h" #include "ir/type.h" #include "memorypool.h" TCResult ast::IfStmt::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); using Case = sst::IfStmt::Case; auto ret = util::pool(this->loc); fs->pushAnonymousTree(); defer(fs->popTree()); for(auto c : this->cases) { //* here, it is implicit that all the inits of every case live in the same scope. //? we might want to change this eventually? i'm not sure. auto inits = zfu::map(c.inits, [fs](Stmt* s) -> auto { return s->typecheck(fs).stmt(); }); auto cs = Case(c.cond->typecheck(fs).expr(), dcast(sst::Block, c.body->typecheck(fs).stmt()), inits); if(!cs.cond->type->isBoolType() && !cs.cond->type->isPointerType()) error(cs.cond, "non-boolean expression with type '%s' cannot be used as a conditional", cs.cond->type); ret->cases.push_back(cs); iceAssert(ret->cases.back().body); } if(this->elseCase) { ret->elseCase = dcast(sst::Block, this->elseCase->typecheck(fs).stmt()); iceAssert(ret->elseCase); } return TCResult(ret); } TCResult ast::ReturnStmt::typecheck(sst::TypecheckState* fs, fir::Type* infer) { auto ret = util::pool(this->loc); if(fs->isInDeferBlock()) error(this, "cannot 'return' while inside a deferred block"); // ok, get the current function auto fn = fs->getCurrentFunction(); auto retty = fn->returnType; if(this->value) { ret->value = this->value->typecheck(fs, retty).expr(); if(fir::getCastDistance(ret->value->type, retty) < 0) { SpanError::make(SimpleError::make(this->loc, "mismatched type in return statement; function returns '%s', value has type '%s'", retty, ret->value->type))->add(util::ESpan(this->value->loc, strprintf("type '%s'", ret->value->type))) ->append(SimpleError::make(MsgType::Note, fn->loc, "function definition is here:")) ->postAndQuit(); } // ok } else if(!retty->isVoidType()) { error(this, "expected value after 'return'; function return type is '%s'", retty); } ret->expectedType = retty; return TCResult(ret); } static bool checkBlockPathsReturn(sst::TypecheckState* fs, sst::Block* block, fir::Type* retty, std::vector* faulty) { // return value is whether or not the block had a return value; // true if all paths explicitly returned, false if not // this return value is used to determine whether we need to insert a // 'return void' thing. bool ret = false; for(size_t i = 0; i < block->statements.size(); i++) { auto& s = block->statements[i]; if(auto retstmt = dcast(sst::ReturnStmt, s)) { // ok... ret = true; auto t = retstmt->expectedType; iceAssert(t); if(fir::getCastDistance(t, retty) < 0) { if(retstmt->expectedType->isVoidType()) { error(retstmt, "expected value after 'return'; function return type is '%s'", retty); } else { std::string msg; if(block->isSingleExpr) msg = "invalid single-expression with type '%s' in function returning '%s'"; else msg = "mismatched type in return statement; function returns '%s', value has type '%s'"; SpanError::make(SimpleError::make(retstmt->loc, msg.c_str(), retty, retstmt->expectedType)) ->add(util::ESpan(retstmt->value->loc, strprintf("type '%s'", retstmt->expectedType))) ->append(SimpleError::make(MsgType::Note, fs->getCurrentFunction()->loc, "function definition is here:")) ->postAndQuit(); } } if(i != block->statements.size() - 1) { SimpleError::make(block->statements[i + 1]->loc, "unreachable code after return statement") ->append(SimpleError::make(MsgType::Note, retstmt->loc, "return statement was here:")) ->postAndQuit();; } } else /* if(i == block->statements.size() - 1) */ { //* it's our duty to check the internals of these things regardless of their exhaustiveness //* so that we can check for the elision of the merge block. //? eg: if 's' itself does not have an else case, but say one of its branches is exhaustive (all arms return), //? then we can elide the merge block for that branch, even though we can't for 's' itself. //* this isn't strictly necessary (the program is still correct without it), but we generate nicer IR this way. bool exhausted = false; if(auto ifstmt = dcast(sst::IfStmt, s); ifstmt) { bool all = true; for(const auto& c: ifstmt->cases) all = all && checkBlockPathsReturn(fs, c.body, retty, faulty); exhausted = all && ifstmt->elseCase && checkBlockPathsReturn(fs, ifstmt->elseCase, retty, faulty); ifstmt->elideMergeBlock = exhausted; } else if(auto whileloop = dcast(sst::WhileLoop, s); whileloop) { exhausted = checkBlockPathsReturn(fs, whileloop->body, retty, faulty) && whileloop->isDoVariant; whileloop->elideMergeBlock = exhausted; } else if(auto feloop = dcast(sst::ForeachLoop, s); feloop) { // we don't set 'exhausted' here beacuse for loops cannot be guaranteed to be exhaustive. // but we still want to check the block inside for elision. feloop->elideMergeBlock = checkBlockPathsReturn(fs, feloop->body, retty, faulty); } ret = exhausted; } } return ret; } bool sst::TypecheckState::checkAllPathsReturn(FunctionDefn* fn) { fir::Type* expected = fn->returnType; std::vector faults { fn->body }; auto ret = checkBlockPathsReturn(this, fn->body, expected, &faults); if(!expected->isVoidType() && !ret) { auto err = SimpleError::make(fn->loc, "not all paths return a value; expected value of type '%s'", expected); for(auto b : faults) err->append(SimpleError::make(MsgType::Note, b->closingBrace, "potentially missing return statement here:")); err->postAndQuit(); } return ret; } ================================================ FILE: source/typecheck/defer.cpp ================================================ // defer.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "errors.h" #include "typecheck.h" #include "memorypool.h" TCResult ast::DeferredStmt::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); // disallow certain things from being deferred auto ret = this->actual->typecheck(fs, infer).stmt(); std::function)> checkRecursively = [&checkRecursively](const Location& loc, std::vector stmts) -> void { for(auto stmt : stmts) { if(dcast(sst::Defn, stmt)) { SimpleError::make(stmt->loc, "definitions cannot be deferred") ->append(SimpleError::make(MsgType::Note, loc, "in deferred block here:")) ->postAndQuit(); } else if(dcast(sst::BreakStmt, stmt) || dcast(sst::ContinueStmt, stmt) || dcast(sst::ReturnStmt, stmt)) { SimpleError::make(stmt->loc, "control flow cannot be deferred") ->append(SimpleError::make(MsgType::Note, loc, "in deferred block here:")) ->postAndQuit(); } else if(auto hb = dcast(sst::HasBlocks, stmt)) { for(auto b : hb->getBlocks()) checkRecursively(loc, b->statements); } } }; if(auto b = dcast(sst::Block, ret)) checkRecursively(this->loc, b->statements); else checkRecursively(this->loc, { ret }); return TCResult(ret); } ================================================ FILE: source/typecheck/destructure.cpp ================================================ // destructure.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "errors.h" #include "typecheck.h" #include "ir/type.h" #include "memorypool.h" static void checkAndAddBinding(sst::TypecheckState* fs, DecompMapping* bind, fir::Type* rhs, bool immut, bool allowref); static void checkTuple(sst::TypecheckState* fs, DecompMapping* bind, fir::Type* rhs, bool immut) { iceAssert(!bind->array); if(!rhs->isTupleType()) error(bind->loc, "expected tuple type in destructuring declaration; found type '%s' instead", rhs); auto tty = rhs->toTupleType(); if(bind->inner.size() != tty->getElementCount()) { error(bind->loc, "too %s bindings in destructuring declaration; expected %d, found %d instead", (bind->inner.size() < tty->getElementCount() ? "few" : "many"), tty->getElementCount(), bind->inner.size()); } for(size_t i = 0; i < tty->getElementCount(); i++) checkAndAddBinding(fs, &bind->inner[i], tty->getElementN(i), immut, true); } static void checkArray(sst::TypecheckState* fs, DecompMapping* bind, fir::Type* rhs, bool immut) { iceAssert(bind->array); if(!rhs->isArrayType() && !rhs->isDynamicArrayType() && !rhs->isArraySliceType() && !rhs->isStringType()) error(bind->loc, "expected array type in destructuring declaration; found type '%s' instead", rhs); if(rhs->isStringType()) { //* note: special-case this, because 1. we want to return chars, but 2. strings are supposed to be immutable. for(auto& b : bind->inner) checkAndAddBinding(fs, &b, fir::Type::getInt8(), immut, false); if(!bind->restName.empty()) { auto fake = util::pool(bind->loc); fake->id = Identifier(bind->restName, IdKind::Name); fake->immutable = immut; //* note: see typecheck/slices.cpp for mutability rules. if(bind->restRef) fake->type = fir::Type::getCharSlice(sst::getMutabilityOfSliceOfType(rhs)); else fake->type = fir::Type::getString(); fs->stree->addDefinition(bind->restName, fake); bind->restDefn = fake; } } else { for(auto& b : bind->inner) checkAndAddBinding(fs, &b, rhs->getArrayElementType(), immut, true); if(!bind->restName.empty()) { auto fake = util::pool(bind->loc); fake->id = Identifier(bind->restName, IdKind::Name); fake->immutable = immut; //* note: see typecheck/slices.cpp for mutability rules. if(bind->restRef || rhs->isArraySliceType()) fake->type = fir::ArraySliceType::get(rhs->getArrayElementType(), sst::getMutabilityOfSliceOfType(rhs)); else fake->type = fir::DynamicArrayType::get(rhs->getArrayElementType()); fs->stree->addDefinition(bind->restName, fake); bind->restDefn = fake; } } } static void checkAndAddBinding(sst::TypecheckState* fs, DecompMapping* bind, fir::Type* rhs, bool immut, bool allowref) { if(!bind->name.empty()) { if(bind->name != "_") { auto fake = util::pool(bind->loc); fake->id = Identifier(bind->name, IdKind::Name); fake->immutable = immut; if(bind->ref && !allowref) error(bind->loc, "cannot bind to value of type '%s' by reference", rhs); else if(bind->ref) fake->type = rhs->getPointerTo(); else fake->type = rhs; fs->stree->addDefinition(bind->name, fake); bind->createdDefn = fake; } } else if(bind->array) { checkArray(fs, bind, rhs, immut); } else { checkTuple(fs, bind, rhs, immut); } } DecompMapping sst::TypecheckState::typecheckDecompositions(const DecompMapping& bind, fir::Type* rhs, bool immut, bool allowref) { auto copy = bind; checkAndAddBinding(this, ©, rhs, immut, allowref); return copy; } TCResult ast::DecompVarDefn::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); auto ret = util::pool(this->loc); ret->immutable = this->immut; if(auto splat = dcast(ast::SplatOp, this->initialiser)) { if(this->bindings.array) { SpanError::make(SimpleError::make(this->loc, "value splats can only be assigned to tuple decompositions")) ->add(util::ESpan(this->initialiser->loc, "")) ->postAndQuit(); } bool isnest = false; for(const auto& b : this->bindings.inner) { if(b.name.empty()) { isnest = true; break; } } if(isnest) { SpanError::make(SimpleError::make(this->loc, "cannot assign value splats to nested tuple decomposition")) ->add(util::ESpan(this->initialiser->loc, "")) ->postAndQuit(); } // ok, at this point we should be fine. this->initialiser = util::pool(splat->loc, std::vector(this->bindings.inner.size(), splat->expr)); } ret->init = this->initialiser->typecheck(fs).expr(); ret->bindings = fs->typecheckDecompositions(this->bindings, ret->init->type, this->immut, false); return TCResult(ret); } ================================================ FILE: source/typecheck/directives.cpp ================================================ // directives.cpp // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "pts.h" #include "errors.h" #include "resolver.h" #include "codegen.h" #include "typecheck.h" #include "ir/type.h" #include "ir/interp.h" #include "memorypool.h" TCResult ast::RunDirective::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); auto rundir = util::pool(this->loc, nullptr); if(this->insideExpr) { rundir->insideExpr = this->insideExpr->typecheck(fs, infer).expr(); rundir->type = rundir->insideExpr->type; } else { rundir->block = dcast(sst::Block, this->block->typecheck(fs, infer).stmt()); iceAssert(rundir->block); rundir->type = fir::Type::getVoid(); } return TCResult(rundir); } // defined in codegen/directives.cpp fir::ConstantValue* magicallyRunExpressionAtCompileTime(cgn::CodegenState* cs, sst::Stmt* stmt, fir::Type* infer, const fir::Name& fname, fir::interp::InterpState* is = 0); static size_t condCounter = 0; TCResult ast::IfDirective::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); // the entire point of #if is that when the condition is false, we don't typecheck it at all. // (of course, it must still parse.) in order to achieve this, together with arbitrary code in the // conditions, we first need to codegen anything that might have been seen -- eg. globals, functions, etc, // so that we can run the interpreter. // thus, we need to *run codegen* *right now*, to get a module. we don't call cgn::codegen directly, but we setup the // internals ourselves, since cgn::codegen expects a fully typechecked module/dtree, which we don't have right now auto mod = new fir::Module(""); auto cs = new cgn::CodegenState(fir::IRBuilder(mod)); cs->typeDefnMap = fs->typeDefnMap; cs->module = mod; // so we don't crash, give us a starting location. cs->pushLoc(this->loc); defer(delete cs); defer(delete mod); sst::Block* execBlock = 0; for(auto c : this->cases) { if(!c.inits.empty()) error(c.inits[0], "compile-time #if currently does not support initialisers"); auto cond = c.cond->typecheck(fs, fir::Type::getBool()).expr(); auto value = magicallyRunExpressionAtCompileTime(cs, cond, fir::Type::getBool(), fir::Name::obfuscate("interp_if_cond", condCounter++)); if(!value->getType()->isBoolType()) error(c.cond, "expression with non-boolean type '%s' cannot be used as a conditional in an #if", value->getType()); auto b = dcast(fir::ConstantBool, value); iceAssert(b); if(b->getValue() == true) // be a bit explicit { execBlock = dcast(sst::Block, c.body->typecheck(fs).stmt()); iceAssert(execBlock); break; } } if(!execBlock && this->elseCase) { execBlock = dcast(sst::Block, this->elseCase->typecheck(fs).stmt()); iceAssert(execBlock); } if(!execBlock) { return TCResult::getDummy(); } else { return TCResult(execBlock); } } ================================================ FILE: source/typecheck/dotop.cpp ================================================ // dotop.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "errors.h" #include "typecheck.h" #include "gluecode.h" #include "resolver.h" #include "polymorph.h" #include "ir/type.h" #include "memorypool.h" namespace names = strs::names; // make the nice message. static ErrorMsg* wrongDotOpError(ErrorMsg* e, sst::StructDefn* str, const Location& l, const std::string& name, bool usedStatic) { if(usedStatic) { // check static ones for a better error message. sst::Defn* found = 0; for(auto sm : str->methods) if(sm->id.name == name) { found = sm; break; } if(!found) { for(auto sf : str->fields) if(sf->id.name == name) { found = sf; break; } } if(found) e->append(SimpleError::make(MsgType::Note, found->loc, "use '.' to refer to the instance member '%s'", name)); return e; } else { if(auto cls = dcast(sst::ClassDefn, str)) { // check static ones for a better error message. sst::Defn* found = 0; for(auto sm : cls->staticMethods) if(sm->id.name == name) { found = sm; break; } if(!found) { for(auto sf : cls->staticFields) if(sf->id.name == name) { found = sf; break; } } if(found) e->append(SimpleError::make(MsgType::Note, found->loc, "use '::' to refer to the static member '%s'", name)); } return e; } }; struct search_result_t { search_result_t() { } search_result_t(fir::Type* t, size_t i, bool tr) : type(t), fieldIdx(i), isTransparent(tr) { } fir::Type* type = 0; size_t fieldIdx = 0; bool isTransparent = false; }; static std::vector searchTransparentFields(sst::TypecheckState* fs, std::vector stack, const std::vector& fields, const Location& loc, const std::string& name) { // search for them by name first, instead of doing a super-depth-first-search. for(auto df : fields) { if(df->id.name == name) { stack.push_back(search_result_t(df->type, 0, false)); return stack; } } size_t idx = 0; for(auto df : fields) { if(df->isTransparentField) { auto ty = df->type; iceAssert(ty->isRawUnionType() || ty->isStructType()); auto defn = fs->typeDefnMap[ty]; iceAssert(defn); std::vector flds; if(auto str = dcast(sst::StructDefn, defn); str) flds = str->fields; else if(auto unn = dcast(sst::RawUnionDefn, defn); unn) flds = zfu::map(unn->fields, zfu::pair_second()) + unn->transparentFields; else error(loc, "what kind of type is this? '%s'", ty); stack.push_back(search_result_t(ty, idx, true)); auto ret = searchTransparentFields(fs, stack, flds, loc, name); if(!ret.empty()) return ret; else stack.pop_back(); } idx += 1; } // if we've reached the end of the line, return nothing. return { }; } static sst::FieldDotOp* resolveFieldNameDotOp(sst::TypecheckState* fs, sst::Expr* lhs, const std::vector& fields, const Location& loc, const std::string& name) { for(auto df : fields) { if(df->id.name == name) { auto ret = util::pool(loc, df->type); ret->lhs = lhs; ret->rhsIdent = name; return ret; } } // sad. search for the field, recursively, in transparent members. auto ops = searchTransparentFields(fs, { }, fields, loc, name); if(ops.empty()) return nullptr; // ok, now we just need to make a link of fielddotops... sst::Expr* cur = lhs; for(const auto& x : ops) { auto op = util::pool(loc, x.type); op->lhs = cur; op->isTransparentField = x.isTransparent; op->indexOfTransparentField = x.fieldIdx; // don't set a name if we're transparent. op->rhsIdent = (x.isTransparent ? "" : name); cur = op; } auto ret = dcast(sst::FieldDotOp, cur); iceAssert(ret); return ret; } static sst::Expr* doExpressionDotOp(sst::TypecheckState* fs, ast::DotOperator* dotop, fir::Type* infer) { auto lhs = dotop->left->typecheck(fs).expr(); // first we got to find the struct defn based on the type auto type = lhs->type; if(!type) { if(dcast(sst::ScopeExpr, lhs)) { error(dotop, "invalid use of '.' for static scope access; use '::' instead"); } else { error(lhs, "failed to resolve type of lhs in expression dot-op!"); } } else if(auto vr = dcast(sst::VarRef, lhs); vr && (dcast(sst::UnionDefn, vr->def) || dcast(sst::EnumDefn, vr->def))) { error(dotop, "use '::' to access enumeration cases and union variants"); } if(type->isTupleType()) { ast::LitNumber* ln = dcast(ast::LitNumber, dotop->right); if(!ln) error(dotop->right, "right-hand side of dot-operator on tuple type ('%s') must be a number literal", type); if(ln->num.find(".") != std::string::npos || ln->num.find("-") != std::string::npos) error(dotop->right, "tuple indices must be non-negative integer numerical literals"); size_t n = std::stoul(ln->num); auto tup = type->toTupleType(); if(n >= tup->getElementCount()) error(dotop->right, "tuple only has %d elements, cannot access element %d", tup->getElementCount(), n); auto ret = util::pool(dotop->loc, tup->getElementN(n)); ret->lhs = lhs; ret->index = n; return ret; } else if(type->isPointerType() && (type->getPointerElementType()->isStructType() || type->getPointerElementType()->isClassType())) { type = type->getPointerElementType(); //* note: it's in the else-if here because we currently don't support auto deref-ing (ie. use '.' on pointers) //* for builtin types, only for classes and structs. // TODO: reevaluate this decision? } else if(type->isStringType()) { auto rhs = dotop->right; if(auto vr = dcast(ast::Ident, rhs)) { // TODO: Extension support here fir::Type* res = 0; if(zfu::match(vr->name, names::saa::FIELD_LENGTH, names::saa::FIELD_CAPACITY, names::saa::FIELD_REFCOUNT, names::string::FIELD_COUNT)) { res = fir::Type::getNativeWord(); } else if(vr->name == names::saa::FIELD_POINTER) { res = fir::Type::getInt8Ptr(); } if(res) { auto tmp = util::pool(dotop->right->loc, res); tmp->lhs = lhs; tmp->name = vr->name; return tmp; } // else: break out below, for extensions } else if(auto fc = dcast(ast::FunctionCall, rhs)) { fir::Type* res = 0; std::vector args; if(fc->name == names::saa::FN_CLONE) { res = type; if(fc->args.size() != 0) error(fc, "builtin string method 'clone' expects exactly 0 arguments, found %d instead", fc->args.size()); } else if(fc->name == names::saa::FN_APPEND) { res = fir::Type::getVoid(); if(fc->args.size() != 1) error(fc, "builtin string method 'append' expects exactly 1 argument, found %d instead", fc->args.size()); else if(!fc->args[0].first.empty()) error(fc, "argument to builtin method 'append' cannot be named"); args.push_back(fc->args[0].second->typecheck(fs).expr()); if(!args[0]->type->isCharType() && !args[0]->type->isStringType() && !args[0]->type->isCharSliceType()) { error(fc, "invalid argument type '%s' to builtin string method 'append'; expected one of '%s', '%s', or '%s'", args[0]->type, fir::Type::getInt8(), fir::Type::getCharSlice(false), fir::Type::getString()); } } if(res) { auto tmp = util::pool(dotop->right->loc, res); tmp->lhs = lhs; tmp->args = args; tmp->name = fc->name; tmp->isFunctionCall = true; return tmp; } } } else if(type->isDynamicArrayType() || type->isArraySliceType() || type->isArrayType()) { auto rhs = dotop->right; if(auto vr = dcast(ast::Ident, rhs)) { fir::Type* res = 0; if(vr->name == names::saa::FIELD_LENGTH || (type->isDynamicArrayType() && zfu::match(vr->name, names::saa::FIELD_CAPACITY, names::saa::FIELD_REFCOUNT))) { res = fir::Type::getNativeWord(); } else if(vr->name == names::saa::FIELD_POINTER) { res = type->getArrayElementType()->getPointerTo(); if(type->isDynamicArrayType()) res = res->getMutablePointerVersion(); else if(type->isArraySliceType() && type->toArraySliceType()->isMutable()) res = res->getMutablePointerVersion(); } if(res) { auto tmp = util::pool(dotop->right->loc, res); tmp->lhs = lhs; tmp->name = vr->name; return tmp; } // else: break out below, for extensions } else if(auto fc = dcast(ast::FunctionCall, rhs)) { fir::Type* res = 0; std::vector args; if(fc->name == names::saa::FN_CLONE) { res = type; if(fc->args.size() != 0) error(fc, "builtin array method 'clone' expects exactly 0 arguments, found %d instead", fc->args.size()); } else if(fc->name == names::saa::FN_APPEND) { if(type->isArrayType()) error(fc, "'append' method cannot be called on arrays"); res = fir::DynamicArrayType::get(type->getArrayElementType()); if(fc->args.size() != 1) error(fc, "builtin array method 'append' expects exactly 1 argument, found %d instead", fc->args.size()); else if(!fc->args[0].first.empty()) error(fc, "argument to builtin method 'append' cannot be named"); args.push_back(fc->args[0].second->typecheck(fs).expr()); if(args[0]->type != type->getArrayElementType() //? vv logic below looks a little sketch. && ((args[0]->type->isArraySliceType() && args[0]->type->getArrayElementType() != type->getArrayElementType())) && args[0]->type != type) { error(fc, "invalid argument type '%s' to builtin array method 'append'; expected one of '%s', '%s', or '%s'", args[0]->type, type, type->getArrayElementType(), fir::ArraySliceType::get(type->getArrayElementType(), false)); } } else if(fc->name == names::array::FN_POP) { if(!type->isDynamicArrayType()) error(fc, "'pop' method can only be called on dynamic arrays"); res = type->getArrayElementType(); if(fc->args.size() != 0) error(fc, "builtin array method 'pop' expects no arguments, found %d instead", fc->args.size()); } // fallthrough if(res) { auto tmp = util::pool(dotop->right->loc, res); tmp->lhs = lhs; tmp->args = args; tmp->name = fc->name; tmp->isFunctionCall = true; return tmp; } } } else if(type->isEnumType()) { // allow getting name, raw and value auto rhs = dotop->right; if(auto vr = dcast(ast::Ident, rhs)) { // TODO: Extension support here fir::Type* res = 0; if(vr->name == names::enumeration::FIELD_NAME) res = fir::Type::getCharSlice(false); else if(vr->name == names::enumeration::FIELD_INDEX) res = fir::Type::getNativeWord(); else if(vr->name == names::enumeration::FIELD_VALUE) res = type->toEnumType()->getCaseType(); if(res) { auto tmp = util::pool(dotop->right->loc, res); tmp->lhs = lhs; tmp->name = vr->name; return tmp; } // else: break out below, for extensions } } else if(type->isRangeType()) { auto rhs = dotop->right; if(auto vr = dcast(ast::Ident, rhs)) { // TODO: extension support here fir::Type* res = 0; if(vr->name == names::range::FIELD_BEGIN || vr->name == names::range::FIELD_END || vr->name == names::range::FIELD_STEP) res = fir::Type::getNativeWord(); if(res) { auto tmp = util::pool(dotop->right->loc, res); tmp->lhs = lhs; tmp->name = vr->name; return tmp; } } // else: fallthrough; } else if(type->isAnyType()) { auto rhs = dotop->right; if(auto vr = dcast(ast::Ident, rhs)) { // TODO: extension support here fir::Type* res = 0; if(vr->name == names::any::FIELD_TYPEID) res = fir::Type::getNativeUWord(); else if(vr->name == names::any::FIELD_REFCOUNT) res = fir::Type::getNativeWord(); if(res) { auto tmp = util::pool(dotop->right->loc, res); tmp->lhs = lhs; tmp->name = vr->name; return tmp; } } // else: fallthrough } // ok. auto defn = fs->typeDefnMap[type]; // note: if `defn` is null, then all the dcasts will fail and we'll // fallthrough to the bottom. if(auto str = dcast(sst::StructDefn, defn)) { // right. if(auto fc = dcast(ast::FunctionCall, dotop->right)) { fs->pushSelfContext(str->type); defer(fs->popSelfContext()); // check methods first std::vector arguments = zfu::map(fc->args, [fs](auto arg) -> FnCallArgument { return FnCallArgument(arg.second->loc, arg.first, arg.second->typecheck(fs).expr(), arg.second); }); //! SELF HANDLING (INSERTION) (DOT-METHOD-CALL) //* note: how we handle this is that we insert the self argument to interface with our resolver, //* then remove it below since our codegen will handle the actual insertion. arguments.insert(arguments.begin(), FnCallArgument::make(fc->loc, "this", str->type->getMutablePointerTo(), /* ignoreName: */ true)); fs->teleportInto(str->innerScope); ErrorMsg* err = 0; sst::Defn* resolved = 0; auto curstr = str; while(!resolved) { auto arg_copy = arguments; auto res = sst::resolver::resolveFunctionCall(fs, fc->loc, fc->name, &arg_copy, fc->mappings, /* traverseUp: */ false, infer); if(res.isDefn()) { resolved = res.defn(); break; } if(auto cls = dcast(sst::ClassDefn, curstr); cls && cls->baseClass) { // teleport out, then back in. fs->teleportOut(); fs->teleportInto(cls->baseClass->innerScope); curstr = cls->baseClass; continue; } // sighs err = res.error(); break; } if(!resolved) { iceAssert(err); wrongDotOpError(SimpleError::make(fc->loc, "no valid call to method named '%s' in type '%s'%s", fc->name, str->id.name, curstr != str ? " (or any of its parent types)" : ""), str, fc->loc, fc->name, false)->append(err)->postAndQuit(); } sst::Expr* finalCall = 0; if(auto fndef = dcast(sst::FunctionDefn, resolved); fndef) { auto c = util::pool(fc->loc, resolved->type->toFunctionType()->getReturnType()); c->arguments = arguments; c->name = fc->name; c->target = resolved; c->isImplicitMethodCall = false; //! SELF HANDLING (REMOVAL) (DOT-METHOD-CALL) c->arguments.erase(c->arguments.begin(), c->arguments.begin() + 1); finalCall = c; } else { auto c = util::pool(fc->loc, resolved->type->toFunctionType()->getReturnType()); c->arguments = zfu::map(arguments, [](const FnCallArgument& e) -> sst::Expr* { return e.value; }); auto tmp = util::pool(fc->loc, resolved->type); tmp->lhs = lhs; tmp->rhsIdent = fc->name; c->callee = tmp; //! SELF HANDLING (REMOVAL) (DOT-METHOD-CALL) c->arguments.erase(c->arguments.begin(), c->arguments.begin() + 1); finalCall = c; } auto ret = util::pool(fc->loc, resolved->type->toFunctionType()->getReturnType()); ret->lhs = lhs; ret->call = finalCall; fs->teleportOut(); return ret; } else if(auto fld = dcast(ast::Ident, dotop->right)) { auto name = fld->name; { auto copy = str; while(copy) { auto hmm = resolveFieldNameDotOp(fs, lhs, copy->fields, dotop->loc, name); if(hmm) return hmm; // ok, we didn't find it. if(auto cls = dcast(sst::ClassDefn, copy); cls) copy = cls->baseClass; else copy = nullptr; } } // check for method references std::vector meths; for(auto m : str->methods) { if(m->id.name == name) meths.push_back(m); } if(meths.empty()) { wrongDotOpError(SimpleError::make(fld->loc, "no field named '%s' in type '%s'", fld->name, str->id.name), str, fld->loc, fld->name, false)->postAndQuit(); } else { // ok, we potentially have a method -- if we used '.', error out. if(!dotop->isStatic) error(dotop, "use '::' to refer to a method of a type"); fir::Type* retty = 0; // ok, disambiguate if we need to if(meths.size() == 1) { retty = meths[0]->type; } else { // ok, we need to. if(infer == 0) { auto err = SimpleError::make(dotop->right->loc, "ambiguous reference to method '%s' in struct '%s'", name, str->id.name); for(auto m : meths) err->append(SimpleError::make(MsgType::Note, m->loc, "potential target here:")); err->postAndQuit(); } // else... if(!infer->isFunctionType()) { error(dotop->right, "non-function type '%s' inferred for reference to method '%s' of struct '%s'", infer, name, str->id.name); } // ok. for(auto m : meths) { if(m->type == infer) { retty = m->type; break; } } // hm, okay error(dotop->right, "no matching method named '%s' with signature '%s' to match inferred type", name, infer); } auto ret = util::pool(dotop->loc, retty); ret->lhs = lhs; ret->rhsIdent = name; ret->isMethodRef = true; return ret; } } else { error(dotop->right, "unsupported right-side expression for dot-operator on type '%s'", str->id.name); } } else if(auto rnn = dcast(sst::RawUnionDefn, defn)) { if(auto fld = dcast(ast::Ident, dotop->right)) { auto flds = zfu::map(rnn->fields, zfu::pair_second()) + rnn->transparentFields; auto hmm = resolveFieldNameDotOp(fs, lhs, flds, dotop->loc, fld->name); if(hmm) { return hmm; } else { // ok we didn't return. this is a raw union so extensions R NOT ALLOWED!! (except methods maybe) error(fld, "union '%s' has no member named '%s'", rnn->id.name, fld->name); } } else { error(dotop->right, "unsupported right-side expression for dot-operator on type '%s'", defn->id.name); } } else { // TODO: this error message could be better!!! //* it's because we are pending extension support! error(lhs, "unsupported left-side expression (with type '%s') for dot-operator", lhs->type); } // TODO: plug in extensions here!! } static sst::Expr* checkRhs2(sst::TypecheckState* fs, ast::DotOperator* dot, const sst::Scope& olds, const sst::Scope& news, fir::Type* rhs_infer, sst::StructDefn* possibleStructDefn = 0) { if(auto id = dcast(ast::Ident, dot->right)) id->traverseUpwards = false; else if(auto fc = dcast(ast::FunctionCall, dot->right)) fc->traverseUpwards = false; // note: for function/expr calls, we typecheck the arguments *before* we teleport to the scope, so that we don't conflate // the scope of the argument (which is the current scope) with the scope of the call target (which is in whatever namespace) sst::Expr* ret = 0; if(auto fc = dcast(ast::FunctionCall, dot->right)) { auto args = zfu::map(fc->args, [fs](auto e) -> FnCallArgument { return FnCallArgument(e.second->loc, e.first, e.second->typecheck(fs).expr(), e.second); }); fs->teleportInto(news); ret = fc->typecheckWithArguments(fs, args, rhs_infer); } else if(auto ec = dcast(ast::ExprCall, dot->right)) { auto args = zfu::map(fc->args, [fs](auto e) -> FnCallArgument { return FnCallArgument(e.second->loc, e.first, e.second->typecheck(fs).expr(), e.second); }); fs->teleportInto(news); ret = ec->typecheckWithArguments(fs, args, rhs_infer); } else if(dcast(ast::Ident, dot->right) || dcast(ast::DotOperator, dot->right)) { fs->teleportInto(news); auto res = dot->right->typecheck(fs, rhs_infer); if(res.isError() && possibleStructDefn && dcast(ast::Ident, dot->right)) { wrongDotOpError(res.error(), possibleStructDefn, dot->right->loc, dcast(ast::Ident, dot->right)->name, true)->postAndQuit(); } else { // will post if res is an error, even if we didn't give the fancy error. ret = res.expr(); } } else { error(dot->right, "unexpected %s on right-side of dot-operator following static scope '%s' on the left", dot->right->readableName, news.string()); } iceAssert(ret); fs->teleportOut(); return ret; } static sst::Expr* doStaticDotOp(sst::TypecheckState* fs, ast::DotOperator* dot, sst::Expr* left, fir::Type* infer) { // if we get a type expression, then we want to dig up the definition from the type. if(auto ident = dcast(sst::VarRef, left); ident || dcast(sst::TypeExpr, left)) { sst::Defn* def = 0; if(ident) { def = ident->def; } else { auto te = dcast(sst::TypeExpr, left); iceAssert(te); def = fs->typeDefnMap[te->type]; } if(!def) { error(left->loc, "could not resolve definition"); } if(auto typdef = dcast(sst::TypeDefn, def)) { if(dcast(sst::ClassDefn, def) || dcast(sst::StructDefn, def)) { fs->pushSelfContext(def->type); auto oldscope = fs->scope(); auto newscope = typdef->innerScope; fs->pushGenericContext(); defer(fs->popGenericContext()); { int pses = sst::poly::internal::getNextSessionId(); iceAssert(typdef->original); for(auto g : typdef->original->generics) fs->addGenericMapping(g.first, fir::PolyPlaceholderType::get(g.first, pses)); } auto ret = checkRhs2(fs, dot, oldscope, newscope, infer); fs->popSelfContext(); return ret; } else if(auto unn = dcast(sst::UnionDefn, def)) { bool wasfncall = false; std::string name; if(auto fc = dcast(ast::FunctionCall, dot->right)) { wasfncall = true; name = fc->name; } else if(auto id = dcast(ast::Ident, dot->right)) { name = id->name; } else { error(dot->right, "unexpected right-hand expression on dot-operator on union '%s'", unn->id.name); } if(!unn->type->toUnionType()->hasVariant(name)) { SimpleError::make(dot->right->loc, "union '%s' has no variant '%s'", unn->id.name, name) ->append(SimpleError::make(MsgType::Note, unn->loc, "union was defined here:")) ->postAndQuit(); } else if(!wasfncall && unn->type->containsPlaceholders() && infer == nullptr) { // note that we check infer == 0 before giving this error. // we should be able to pass in the infer value such that it works properly // eg. let x: Foo = Foo.none SimpleError::make(dot->right->loc, "could not infer type parameters for polymorphic union '%s' using variant '%s' ", unn->id.name, name)->append(SimpleError::make(MsgType::Note, unn->variants[name]->loc, "variant was defined here:"))->postAndQuit(); } else if(wasfncall && unn->type->toUnionType()->getVariants().at(name)->getInteriorType()->isVoidType()) { SimpleError::make(dot->right->loc, "variant '%s' of union does not have values, and cannot be constructed via function-call", name, unn->id.name)->append(SimpleError::make(MsgType::Note, unn->variants[name]->loc, "variant was defined here:"))->postAndQuit(); } // dot-op on the union to access its variants; we need constructor stuff for it. auto oldscope = fs->scope(); auto newscope = unn->innerScope; return checkRhs2(fs, dot, oldscope, newscope, infer); } else if(auto enm = dcast(sst::EnumDefn, def)) { auto oldscope = fs->scope(); auto newscope = enm->innerScope; auto rhs = checkRhs2(fs, dot, oldscope, newscope, infer); if(auto vr = dcast(sst::VarRef, rhs)) { iceAssert(vr->def && enm->cases[vr->name] == vr->def); return vr; } else { error(rhs, "unsupported right-hand expression on enum '%s'", enm->id.name); } } else { error(dot, "static access is not supported on type '%s'", def->type); } } else { error(dot, "invalid static access on variable (of type '%s'); use '.' to refer to instance members", def->type); } } else if(auto scp = dcast(sst::ScopeExpr, left)) { auto oldscope = fs->scope(); auto newscope = scp->scope; return checkRhs2(fs, dot, oldscope, newscope, infer); } error("????!!!!"); } TCResult ast::DotOperator::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); this->left->checkAsType = this->checkAsType; this->right->checkAsType = this->checkAsType; if(this->isStatic) return TCResult(doStaticDotOp(fs, this, this->left->typecheck(fs).expr(), infer)); else return TCResult(doExpressionDotOp(fs, this, infer)); } ================================================ FILE: source/typecheck/enums.cpp ================================================ // enums.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "errors.h" #include "typecheck.h" #include "ir/type.h" #include "memorypool.h" /* ok, here's some documentation of how enumerations work they're basically strong enums, unlike C enums. you can cast them to ints, and they'll be numbered appropriately starting at 0. each enumeration value is a struct: { index: i64, value: $T } the index is the index of the thing, and allows some runtime things on the enum; for example, a value of type enumeration can have a .name, and in the future can simplify runtime type information getting by having a simpler array-index mechanism. so, a fir::EnumType will now be like a StringType, opaque-ish thing. we'll have IRB things in a similar fashion (it'll be a value type), and that's about it. */ TCResult ast::EnumDefn::generateDeclaration(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) { fs->pushLoc(this); defer(fs->popLoc()); auto [ success, ret ] = this->checkForExistingDeclaration(fs, gmaps); if(!success) return TCResult::getParametric(); else if(ret) return TCResult(ret); auto defnname = util::typeParamMapToString(this->name, gmaps); auto defn = util::pool(this->loc); defn->bareName = this->name; defn->id = Identifier(defnname, IdKind::Type); defn->id.scope = this->enclosingScope; defn->visibility = this->visibility; defn->original = this; defn->enclosingScope = this->enclosingScope; defn->innerScope = this->enclosingScope.appending(defnname); // set it to void first, because we want to defer typechecking the member type. defn->type = fir::EnumType::get(defn->id.convertToName(), fir::Type::getVoid()); if(auto err = fs->checkForShadowingOrConflictingDefinition(defn, [](auto, auto) -> bool { return true; })) return TCResult(err); defn->enclosingScope.stree->addDefinition(defnname, defn, gmaps); this->genericVersions.push_back({ defn, fs->getGenericContextStack() }); return TCResult(defn); } TCResult ast::EnumDefn::typecheck(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) { fs->pushLoc(this); defer(fs->popLoc()); auto tcr = this->generateDeclaration(fs, infer, gmaps); if(tcr.isParametric()) return tcr; else if(tcr.isError()) error(this, "failed to generate declaration for enum '%s'", this->name); auto defn = dcast(sst::EnumDefn, tcr.defn()); iceAssert(defn); fs->teleportInto(defn->innerScope); if(this->memberType) defn->memberType = fs->convertParserTypeToFIR(this->memberType); else defn->memberType = fir::Type::getNativeWord(); auto ety = defn->type->toEnumType(); iceAssert(ety); ety->setCaseType(defn->memberType); size_t index = 0; for(auto cs : this->cases) { sst::Expr* val = 0; if(cs.value) { iceAssert(defn->memberType); val = cs.value->typecheck(fs, defn->memberType).expr(); if(val->type != defn->memberType) error(cs.value, "mismatched type in enum case value; expected type '%s', but found type '%s'", defn->memberType, val->type); } auto ecd = util::pool(cs.loc); ecd->id = Identifier(cs.name, IdKind::Name); ecd->id.scope = fs->scope(); ecd->type = ety; ecd->parentEnum = defn; ecd->val = val; ecd->index = index++; defn->cases[cs.name] = ecd; fs->stree->addDefinition(cs.name, ecd); } defn->type = ety; fs->teleportOut(); return TCResult(defn); } ================================================ FILE: source/typecheck/function.cpp ================================================ // function.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "errors.h" #include "typecheck.h" #include "polymorph.h" #include "ir/type.h" #include "memorypool.h" TCResult ast::FuncDefn::generateDeclaration(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) { fs->pushLoc(this); defer(fs->popLoc()); auto [ success, ret ] = this->checkForExistingDeclaration(fs, gmaps); if(!success) return TCResult::getParametric(); else if(ret) return TCResult(ret); std::vector ps; std::vector ptys; int polyses = sst::poly::internal::getNextSessionId(); for(auto t : this->params) { auto p = FnParam(t.loc, t.name, sst::poly::internal::convertPtsType(fs, this->generics, t.type, polyses)); if(auto dv = t.defaultValue; dv) { p.defaultVal = dv->typecheck(fs, p.type).expr(); if(p.defaultVal->type != p.type) { error(p.defaultVal, "type mismatch for default value of argument '%s': expected '%s', received '%s' intead", p.name, p.type, p.defaultVal->type); } } ps.push_back(p); ptys.push_back(p.type); } fir::Type* retty = sst::poly::internal::convertPtsType(fs, this->generics, this->returnType, polyses); fir::Type* fnType = fir::FunctionType::get(ptys, retty); auto defn = (infer && infer->isClassType() && this->name == "init" ? util::pool(this->loc) : util::pool(this->loc)); defn->type = fnType; if(this->name != "init") defn->original = this; iceAssert(!infer || (infer->isStructType() || infer->isClassType())); defn->parentTypeForMethod = infer; defn->attrs = this->attrs; defn->bareName = this->name; defn->id = Identifier(this->name, IdKind::Function); defn->id.scope = this->enclosingScope; defn->id.params = ptys; defn->id.returnType = retty; defn->enclosingScope = this->enclosingScope; defn->params = ps; defn->returnType = retty; defn->visibility = this->visibility; defn->global = !fs->isInFunctionBody(); defn->isVirtual = this->isVirtual; defn->isOverride = this->isOverride; defn->isMutating = this->isMutating; if(defn->isVirtual && !defn->parentTypeForMethod) { error(defn, "only methods can be marked 'virtual' or 'override' at this point in time"); } else if(defn->isVirtual && defn->parentTypeForMethod && !defn->parentTypeForMethod->isClassType()) { error(defn, "only methods of a class (which '%s' is not) can be marked 'virtual' or 'override'", defn->parentTypeForMethod->str()); } else if(defn->isMutating && !defn->parentTypeForMethod) { error(defn, "only methods of a type can be marked as mutating with 'mut'"); } auto conflict_err = fs->checkForShadowingOrConflictingDefinition(defn, [defn](sst::TypecheckState* fs, sst::Stmt* other) -> bool { if(auto oth = dcast(sst::FunctionDecl, other)) { // make sure we didn't fuck up somewhere iceAssert(oth->id.name == defn->id.name); return sst::isDuplicateOverload(defn->params, oth->params); } else { // variables and functions always conflict if they're in the same namespace return true; } }); if(conflict_err) return TCResult(conflict_err); if(!defn->type->containsPlaceholders()) defn->enclosingScope.stree->addDefinition(this->name, defn, gmaps); else if(defn->enclosingScope.stree->unresolvedGenericDefs[this->name].empty()) defn->enclosingScope.stree->unresolvedGenericDefs[this->name].push_back(this); // add to our versions. this->genericVersions.push_back({ defn, fs->getGenericContextStack() }); return TCResult(defn); } TCResult ast::FuncDefn::typecheck(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) { fs->pushLoc(this); defer(fs->popLoc()); auto tcr = this->generateDeclaration(fs, infer, gmaps); if(tcr.isParametric()) return tcr; else if(!tcr.isDefn()) error(this, "failed to generate declaration for function '%s'", this->name); auto defn = dcast(sst::FunctionDefn, tcr.defn()); iceAssert(defn); if(this->finishedTypechecking.find(defn) != this->finishedTypechecking.end()) return TCResult(defn); // if we have placeholders, don't bother generating anything. if(!defn->type->containsPlaceholders()) { fs->teleportInto(defn->enclosingScope); fs->enterFunctionBody(defn); fs->pushTree(defn->id.convertToName().mangledWithoutScope()); { // add the arguments to the tree for(auto arg : defn->params) { auto vd = util::pool(arg.loc); vd->id = Identifier(arg.name, IdKind::Name); vd->id.scope = fs->scope(); vd->type = arg.type; fs->stree->addDefinition(arg.name, vd); defn->arguments.push_back(vd); } this->body->isFunctionBody = true; defn->body = dcast(sst::Block, this->body->typecheck(fs, defn->returnType).stmt()); defn->body->isSingleExpr = this->body->isArrow; iceAssert(defn->body); defn->insideTree = fs->stree; } fs->popTree(); fs->leaveFunctionBody(); fs->teleportOut(); // ok, do the check. defn->needReturnVoid = !fs->checkAllPathsReturn(defn); } this->finishedTypechecking.insert(defn); return TCResult(defn); } TCResult ast::ForeignFuncDefn::typecheck(sst::TypecheckState* fs, fir::Type* inferred) { if(this->generatedDecl) return TCResult(this->generatedDecl); fs->pushLoc(this); defer(fs->popLoc()); auto defn = util::pool(this->loc); std::vector ps; for(auto t : this->params) ps.push_back(FnParam(t.loc, t.name, fs->convertParserTypeToFIR(t.type))); auto retty = fs->convertParserTypeToFIR(this->returnType); defn->id = Identifier(this->name, IdKind::Name); defn->bareName = this->name; defn->attrs = this->attrs; defn->params = ps; defn->returnType = retty; defn->visibility = this->visibility; defn->isVarArg = this->isVarArg; // the realname is the actual name of the function. defn->realName = this->realName; defn->isIntrinsic = this->isIntrinsic; if(this->isVarArg) defn->type = fir::FunctionType::getCVariadicFunc(zfu::map(ps, [](const FnParam& p) -> auto { return p.type; }), retty); else defn->type = fir::FunctionType::get(zfu::map(ps, [](const FnParam& p) -> auto { return p.type; }), retty); auto conflict_err = fs->checkForShadowingOrConflictingDefinition(defn, [defn](sst::TypecheckState* fs, sst::Stmt* other) -> bool { if(auto decl = dcast(sst::FunctionDecl, other)) { // make sure we didn't fuck up somewhere iceAssert(decl->id.name == defn->id.name); // check the typelists, then bool ret = fir::Type::areTypeListsEqual( zfu::map(defn->params, [](const FnParam& p) -> fir::Type* { return p.type; }), zfu::map(decl->params, [](const FnParam& p) -> fir::Type* { return p.type; }) ); return ret; } else { // variables and functions always conflict if they're in the same namespace return true; } }); if(conflict_err) return TCResult(conflict_err); this->generatedDecl = defn; fs->stree->addDefinition(this->name, defn); return TCResult(defn); } TCResult ast::Block::typecheck(sst::TypecheckState* fs, fir::Type* inferred) { fs->pushLoc(this); defer(fs->popLoc()); if(!this->isFunctionBody && !this->doNotPushNewScope) fs->pushAnonymousTree(); defer((!this->isFunctionBody && !this->doNotPushNewScope) ? fs->popTree() : static_cast(nullptr)); auto ret = util::pool(this->loc); ret->closingBrace = this->closingBrace; if(this->isArrow && this->isFunctionBody) { iceAssert(this->deferredStatements.empty()); iceAssert(this->statements.size() == 1); auto s = this->statements[0]; if(auto e = dcast(ast::Expr, s)) { auto ex = e->typecheck(fs, inferred).expr(); if(inferred && fir::getCastDistance(ex->type, inferred) < 0) { if(inferred->isVoidType()) { ret->statements = { ex }; } else { error(ex, "invalid single-expression with type '%s' in function returning '%s'", ex->type, inferred); } } else { if(!fs->getCurrentFunction()->returnType->isVoidType()) { auto rst = util::pool(s->loc); rst->expectedType = (inferred ? inferred : fs->getCurrentFunction()->returnType); rst->value = ex; ret->statements = { rst }; } else { ret->statements = { ex }; } } } else { error(s, "invalid use of statement in single-expression function body"); } } else { for(auto stmt : this->statements) { if(auto p = dcast(Parameterisable, stmt); p) { p->enclosingScope = fs->scope(); } auto tcr = stmt->typecheck(fs); if(tcr.isError()) return TCResult(tcr.error()); else if(!tcr.isParametric() && !tcr.isDummy()) ret->statements.push_back(tcr.stmt()); } for(auto dstmt : this->deferredStatements) { if(auto p = dcast(Parameterisable, dstmt); p) { p->enclosingScope = fs->scope(); } auto tcr = dstmt->typecheck(fs); if(tcr.isError()) return TCResult(tcr.error()); else if(!tcr.isParametric() && !tcr.isDummy()) ret->deferred.push_back(tcr.stmt()); } } return TCResult(ret); } ================================================ FILE: source/typecheck/literals.cpp ================================================ // literals.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "typecheck.h" #include "ir/type.h" #include "ir/constant.h" #include "memorypool.h" TCResult ast::LitNumber::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); // i don't think mpfr auto-detects base, LMAO int base = 10; if(this->num.find("0x") == 0 || this->num.find("0X") == 0) base = 16; auto number = mpfr::mpreal(this->num, mpfr_get_default_prec(), base); bool sgn = mpfr::signbit(number); bool flt = ((this->num.find(".") != std::string::npos) || !mpfr::isint(number)); size_t bits = 0; if(flt) { // fuck it lah. bits = sizeof(double) * CHAR_BIT; } else { auto m_ptr = number.mpfr_ptr(); auto m_rnd = MPFR_RNDN; if(mpfr_fits_sshort_p(m_ptr, m_rnd)) bits = sizeof(short) * CHAR_BIT; else if(mpfr_fits_sint_p(m_ptr, m_rnd)) bits = sizeof(int) * CHAR_BIT; else if(mpfr_fits_slong_p(m_ptr, m_rnd)) bits = sizeof(long) * CHAR_BIT; else if(mpfr_fits_intmax_p(m_ptr, m_rnd)) bits = sizeof(intmax_t) * CHAR_BIT; else if(!sgn && mpfr_fits_uintmax_p(m_ptr, m_rnd)) bits = sizeof(uintmax_t) * CHAR_BIT; else // lmao bits = sizeof(uintmax_t) * CHAR_BIT; } auto ret = util::pool(this->loc, (infer && infer->isPrimitiveType()) ? infer : fir::ConstantNumberType::get(sgn, flt, bits)); ret->num = number; return TCResult(ret); } TCResult ast::LitNull::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); auto ret = util::pool(this->loc, fir::Type::getNull()); return TCResult(ret); } TCResult ast::LitBool::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); auto ret = util::pool(this->loc, fir::Type::getBool()); ret->value = this->value; return TCResult(ret); } TCResult ast::LitChar::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); auto ret = util::pool(this->loc, fir::Type::getInt8()); ret->value = this->value; return TCResult(ret); } TCResult ast::LitTuple::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); std::vector vals; std::vector fts; if(infer) { if(!infer->isTupleType()) error(this, "assigning tuple to inferred non-tuple type '%s'", infer); auto tt = infer->toTupleType(); if(tt->getElementCount() != this->values.size()) { error(this, "mismatched types in inferred type: have literal with %d elements, inferred type has %d", this->values.size(), tt->getElementCount()); } } size_t k = 0; for(auto v : this->values) { auto inf = (infer ? infer->toTupleType()->getElementN(k) : 0); auto expr = v->typecheck(fs, inf).expr(); auto ty = expr->type; if(expr->type->isConstantNumberType() && (!inf || !inf->isPrimitiveType())) ty = sst::inferCorrectTypeForLiteral(expr->type->toConstantNumberType()); vals.push_back(expr); fts.push_back(ty); k++; } // warn(this, "%s", fir::TupleType::get(fts)); auto ret = util::pool(this->loc, fir::TupleType::get(fts)); ret->values = vals; return TCResult(ret); } TCResult ast::LitString::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); fir::Type* ty = 0; if(this->isCString || (infer && infer == fir::Type::getInt8Ptr())) { ty = fir::Type::getInt8Ptr(); } else { ty = fir::Type::getCharSlice(false); } auto ret = util::pool(this->loc, ty); ret->isCString = this->isCString; ret->str = this->str; return TCResult(ret); } TCResult ast::LitArray::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); std::vector vals; fir::Type* type = 0; if(this->values.empty()) { if(this->explicitType) { auto explty = fs->convertParserTypeToFIR(this->explicitType); iceAssert(explty); type = fir::DynamicArrayType::get(explty); } else { if(infer == 0) { // facilitate passing empty array literals around (that can be cast to a bunch of things like slices and such) infer = fir::DynamicArrayType::get(fir::VoidType::get()); } else if(infer->isArrayType()) { if(infer->toArrayType()->getArraySize() != 0) error(this, "array type with non-zero length %d was inferred for empty array literal", infer->toArrayType()->getArraySize()); } else if(!(infer->isDynamicArrayType() || infer->isArraySliceType())) { error(this, "invalid type '%s' inferred for array literal", infer); } } type = infer; } else { fir::Type* elmty = (this->explicitType ? fs->convertParserTypeToFIR(this->explicitType) : 0); if(!elmty && infer) { if(!infer->isDynamicArrayType() && !infer->isArraySliceType() && !infer->isArrayType()) error(this, "invalid type '%s' inferred for array literal", infer); elmty = infer->getArrayElementType(); } for(auto v : this->values) { auto e = v->typecheck(fs, elmty).expr(); if(!elmty) { if(e->type->isConstantNumberType() && !infer) elmty = sst::inferCorrectTypeForLiteral(e->type->toConstantNumberType()); else elmty = e->type; } else if(elmty != e->type) { error(v, "mismatched type for expression in array literal; expected '%s'%s, found '%s'", elmty, (this->explicitType ? "" : " as inferred from previous elements"), e->type); } if(e->type->isVoidType()) { // be helpful auto err = SimpleError::make(v->loc, "expected value in array literal, found 'void' value instead"); if(auto fc = dcast(sst::FunctionCall, e); fc && fc->target) err->append(SimpleError::make(MsgType::Note, fc->target->loc, "function was defined here:")); err->postAndQuit(); } vals.push_back(e); } //* note: prefer slices by default. // this behaviour changed as of 08/04/2018 if(this->raw || (infer && infer->isArrayType())) { type = fir::ArrayType::get(elmty, this->values.size()); } else if(infer == 0 || infer->isArraySliceType()) { // slices from a constant array generally should remain immutable. type = fir::ArraySliceType::get(elmty, false); } else if(infer->isDynamicArrayType()) { // do something type = fir::DynamicArrayType::get(elmty); } else { error(this, "invalid type '%s' inferred for array literal", infer); } } auto ret = util::pool(this->loc, type); ret->values = vals; return TCResult(ret); } ================================================ FILE: source/typecheck/loops.cpp ================================================ // loops.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "pts.h" #include "ast.h" #include "errors.h" #include "typecheck.h" #include "ir/type.h" #include "memorypool.h" TCResult ast::ForeachLoop::typecheck(sst::TypecheckState* fs, fir::Type* inferred) { fs->pushLoc(this); defer(fs->popLoc()); auto ret = util::pool(this->loc); fs->pushAnonymousTree(); defer(fs->popTree()); ret->array = this->array->typecheck(fs).expr(); fir::Type* elmty = 0; if(ret->array->type->isArrayType() || ret->array->type->isDynamicArrayType() || ret->array->type->isArraySliceType()) elmty = ret->array->type->getArrayElementType(); else if(ret->array->type->isRangeType()) elmty = fir::Type::getNativeWord(); else if(ret->array->type->isStringType()) elmty = fir::Type::getInt8(); else error(this->array, "invalid type '%s' in foreach loop", ret->array->type); iceAssert(elmty); bool allowref = !(ret->array->type->isStringType() || ret->array->type->isRangeType()); if(!this->indexVar.empty()) { auto fake = util::pool(this->loc); fake->name = this->indexVar; fake->type = pts::NamedType::create(this->loc, INTUNSPEC_TYPE_STRING); ret->indexVar = dcast(sst::VarDefn, fake->typecheck(fs).defn()); iceAssert(ret->indexVar); } ret->mappings = fs->typecheckDecompositions(this->bindings, elmty, true, allowref); fs->enterBreakableBody(); { ret->body = dcast(sst::Block, this->body->typecheck(fs).stmt()); iceAssert(ret->body); } fs->leaveBreakableBody(); return TCResult(ret); } TCResult ast::WhileLoop::typecheck(sst::TypecheckState* fs, fir::Type* inferred) { fs->pushLoc(this); defer(fs->popLoc()); sst::WhileLoop* ret = util::pool(this->loc); ret->isDoVariant = this->isDoVariant; fs->pushAnonymousTree(); defer(fs->popTree()); fs->enterBreakableBody(); { ret->body = dcast(sst::Block, this->body->typecheck(fs).stmt()); iceAssert(ret->body); } fs->leaveBreakableBody(); if(this->cond) { ret->cond = this->cond->typecheck(fs, fir::Type::getBool()).expr(); if(ret->cond->type != fir::Type::getBool() && !ret->cond->type->isPointerType()) error(this->cond, "non-boolean expression with type '%s' cannot be used as a conditional", ret->cond->type); } return TCResult(ret); } TCResult ast::BreakStmt::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); if(!fs->isInBreakableBody()) error(this, "cannot 'break' while not inside a loop"); else if(fs->isInDeferBlock()) error(this, "cannot 'break' while inside a deferred block"); return TCResult(util::pool(this->loc)); } TCResult ast::ContinueStmt::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); if(!fs->isInBreakableBody()) error(this, "cannot 'continue' while not inside a loop"); else if(fs->isInDeferBlock()) error(this, "cannot 'continue' while inside a deferred block"); return TCResult(util::pool(this->loc)); } ================================================ FILE: source/typecheck/misc.cpp ================================================ // misc.cpp // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. #include "pts.h" #include "ast.h" #include "errors.h" #include "typecheck.h" #include "ir/type.h" #include "memorypool.h" TCResult ast::PlatformDefn::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); if(this->defnType == Type::Intrinsic) { this->intrinsicDefn->isIntrinsic = true; return this->intrinsicDefn->typecheck(fs, infer); } else if(this->defnType == Type::IntegerType) { auto defn = util::pool(this->loc); // auto opty = fir::OpaqueType::get(this->typeName, this->typeSizeInBits); auto ty = fir::PrimitiveType::getUintN(this->typeSizeInBits); defn->type = ty; defn->id = Identifier(this->typeName, IdKind::Type); defn->id.scope = fs->scope(); fs->checkForShadowingOrConflictingDefinition(defn, [](sst::TypecheckState* fs, sst::Defn* other) -> bool { return true; }); // add it first so we can use it in the method bodies, // and make pointers to it { fs->stree->addDefinition(this->typeName, defn); fs->typeDefnMap[ty] = defn; } return TCResult(defn); } else { return TCResult(SimpleError::make(this->loc, "nani?")); } } ================================================ FILE: source/typecheck/operators.cpp ================================================ // operators.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "errors.h" #include "typecheck.h" #include "ir/type.h" static bool isBuiltinType(fir::Type* ty) { return (ty->isConstantNumberType() || ty->isDynamicArrayType() || ty->isArraySliceType() || ty->isPrimitiveType() || ty->isFunctionType() || ty->isPointerType() || ty->isStringType() || ty->isRangeType() || ty->isArrayType() || ty->isVoidType() || ty->isNullType() || ty->isCharType() || ty->isBoolType()); } static bool isBuiltinOperator(std::string op) { return (op == Operator::Plus || op == Operator::Minus || op == Operator::Multiply || op == Operator::Divide || op == Operator::Modulo || op == Operator::UnaryPlus || op == Operator::UnaryMinus || op == Operator::PointerDeref || op == Operator::AddressOf || op == Operator::BitwiseNot || op == Operator::BitwiseAnd || op == Operator::BitwiseOr || op == Operator::BitwiseXor || op == Operator::BitwiseShiftLeft || op == Operator::BitwiseShiftRight || op == Operator::LogicalNot || op == Operator::LogicalAnd || op == Operator::LogicalOr || op == Operator::CompareEQ || op == Operator::CompareNEQ || op == Operator::CompareLT || op == Operator::CompareLEQ || op == Operator::CompareGT || op == Operator::CompareGEQ || op == Operator::Assign || op == Operator::PlusEquals || op == Operator::MinusEquals || op == Operator::MultiplyEquals || op == Operator::DivideEquals || op == Operator::ModuloEquals || op == Operator::BitwiseShiftLeftEquals || op == Operator::BitwiseShiftRightEquals || op == Operator::BitwiseAndEquals || op == Operator::BitwiseOrEquals || op == Operator::TypeCast || op == Operator::TypeIs || op == "."); } TCResult ast::OperatorOverloadDefn::typecheck(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) { fs->pushLoc(this); defer(fs->popLoc()); if(this->kind == Kind::Invalid) error(this, "invalid operator kind; must be one of 'infix', 'postfix', or 'prefix'"); if(fs->hasSelfContext()) error(this, "operator overloads cannot be methods of a type."); this->generateDeclaration(fs, infer, { }); // call the superclass method. return this->ast::FuncDefn::typecheck(fs, infer, gmaps); } TCResult ast::OperatorOverloadDefn::generateDeclaration(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) { fs->pushLoc(this); defer(fs->popLoc()); auto [ success, ret ] = this->checkForExistingDeclaration(fs, gmaps); if(!success) return TCResult::getParametric(); else if(ret) return TCResult(ret); // there's nothing different. auto defn = dcast(sst::FunctionDefn, this->ast::FuncDefn::generateDeclaration(fs, infer, gmaps).defn()); iceAssert(defn); //! ACHTUNG ! // TODO: is there actually a problem with allowing both types to be user-defined? //? eg we want some_string * 5 to repeat 'some_string' 5 times??? //? is that a legit use-case?? // ok, do our checks on the defn instead. auto ft = defn->type->toFunctionType(); if(this->kind == Kind::Infix) { if(ft->getArgumentCount() != 2) { error(this, "operator overload for binary operator '%s' must have exactly 2 parameters, but %d %s found", this->symbol, ft->getArgumentCount(), ft->getArgumentCount() == 1 ? "was" : "were"); } else if(!Operator::isAssignment(this->symbol) && isBuiltinType(ft->getArgumentN(0)) && isBuiltinType(ft->getArgumentN(1)) && isBuiltinOperator(this->symbol)) { SimpleError::make(this->loc, "binary operator overload (for operator '%s') cannot take two builtin types as arguments (have '%s' and '%s')", this->symbol, ft->getArgumentN(0), ft->getArgumentN(1)) ->append(BareError::make(MsgType::Note, "at least one of the parameters must be a user-defined type")) ->postAndQuit(); } } else if(this->kind == Kind::Postfix || this->kind == Kind::Prefix) { if(ft->getArgumentCount() != 1) { error(this, "operator overload for unary operator '%s' must have exactly 1 parameter, but %d %s found", this->symbol, ft->getArgumentCount(), ft->getArgumentCount() == 1 ? "was" : "were"); } else if(isBuiltinType(ft->getArgumentN(0)) && isBuiltinOperator(this->symbol)) { error(defn->arguments[0], "unary operator '%s' cannot be overloaded for the builtin type '%s'", this->symbol, ft->getArgumentN(0)); } } // ok, further checks. if(Operator::isAssignment(this->symbol)) { if(!ft->getReturnType()->isVoidType()) { error(this, "operator overload for assignment operators (have '%s') must return void, but a return type of '%s' was found", this->symbol, ft->getReturnType()); } else if(!ft->getArgumentN(0)->isPointerType()) { error(defn->arguments[0], "operator overload for assignment operator '%s' must take a pointer to the type as the first parameter, found '%s'", this->symbol, ft->getArgumentN(0)); } else if(isBuiltinType(ft->getArgumentN(0)->getPointerElementType())) { error(defn->arguments[0], "assignment operator '%s' cannot be overloaded for the builtin type '%s'", this->symbol, ft->getArgumentN(0)); } } // before we add, check for duplication. auto thelist = (this->kind == Kind::Infix ? &fs->stree->infixOperatorOverloads : (this->kind == Kind::Prefix ? &fs->stree->prefixOperatorOverloads : &fs->stree->postfixOperatorOverloads)); for(auto it : (*thelist)[this->symbol]) { if(sst::isDuplicateOverload(it->params, defn->params)) { SimpleError::make(this->loc, "duplicate operator overload for '%s' taking identical arguments", this->symbol) ->append(SimpleError::make(MsgType::Note, it->loc, "previous definition was here:")) ->postAndQuit(); } } // ok, we should be good now. (*thelist)[this->symbol].push_back(defn); return TCResult(defn); } ================================================ FILE: source/typecheck/polymorph/driver.cpp ================================================ // driver.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "sst.h" #include "ir/type.h" #include "errors.h" #include "typecheck.h" #include "resolver.h" #include "polymorph.h" #include "memorypool.h" #include namespace sst { namespace poly { std::vector findPolymorphReferences(TypecheckState* fs, const std::string& name, const std::vector& gdefs, const PolyArgMapping_t& pams, fir::Type* return_infer, fir::Type* type_infer, bool isFnCall, std::vector* args) { iceAssert(gdefs.size() > 0); //? now if we have multiple things then we need to try them all, which can get real slow real quick. //? unfortunately I see no better way to do this. // TODO: find a better way to do this?? std::vector pots; for(const auto& gdef : gdefs) { auto [ gmaps, err ] = resolver::misc::canonicalisePolyArguments(fs, gdef, pams); if(err != nullptr) { pots.push_back(PolyRefResult(TCResult(err), Solution_t(), gdef)); } else { auto [ r, s ] = attemptToInstantiatePolymorph(fs, gdef, name, gmaps, return_infer, type_infer, isFnCall, args, /* fillplaceholders: */ true); pots.push_back(PolyRefResult(r, s, gdef)); } } return pots; } namespace internal { static std::pair inferPolymorphicType(TypecheckState* fs, ast::TypeDefn* td, const std::string& name, const ProblemSpace_t& problems, const std::vector& input, const TypeParamMap_t& partial, fir::Type* return_infer, fir::Type* type_infer, bool isFnCall, fir::Type* problem_infer, util::hash_map* origParamOrder) { auto soln = Solution_t(partial); if(!isFnCall && !type_infer) { if(auto missing = getMissingSolutions(problems, soln.solutions, true); missing.size() > 0) { auto ret = solvePolymorphWithPlaceholders(fs, td, name, partial); return { ret.second, nullptr }; } else { return { soln, nullptr }; } } else if(auto cls = dcast(ast::ClassDefn, td)) { util::hash_map paramOrder; auto inputcopy = input; auto selfty = fir::PolyPlaceholderType::get(fir::obfuscateName("self_infer"), getNextSessionId()); inputcopy.insert(inputcopy.begin(), FnCallArgument(fs->loc(), "", util::pool(fs->loc(), selfty->getMutablePointerTo()), 0)); fs->pushSelfContext(selfty); defer(fs->popSelfContext()); std::vector> rets; for(auto init : cls->initialisers) { rets.push_back(inferTypesForPolymorph(fs, init, name, cls->generics, inputcopy, partial, return_infer, type_infer, isFnCall, problem_infer, ¶mOrder)); } // check the distance of all the solutions... i guess? std::pair best; best.first = soln; best.first.distance = INT_MAX; best.second = SimpleError::make(fs->loc(), "ambiguous reference to constructor of class '%s'", cls->name); for(const auto& r : rets) { if(r.first.distance < best.first.distance && r.second == nullptr) best = r; } *origParamOrder = paramOrder; return best; } else if(auto str = dcast(ast::StructDefn, td)) { //* for constructors, we look like a function call, so type_infer is actually return_infer. if(!type_infer && return_infer) { //* so what we do here is, if we have type_infer, we lookup the sst::Defn, and use it to find the matching genericVersion //* in the ast::Defn, and extract the solution map, then recursively call inferPolymorphicType with our new solution. std::swap(type_infer, return_infer); if(auto gen_str = fs->typeDefnMap[type_infer]) { for(const auto& v : str->genericVersions) { if(v.first == gen_str) { return inferPolymorphicType(fs, str, name, problems, input, v.second.back(), /* return_infer: */ nullptr, /* type_infer: */ nullptr, isFnCall, problem_infer, origParamOrder); } } } } std::vector fields; util::hash_map fieldNames; { size_t i = 0; for(auto f : str->fields) { auto nm = std::get<0>(f); fields.push_back(nm); fieldNames[nm] = i++; } } auto [ seen, err ] = resolver::verifyStructConstructorArguments(fs->loc(), str->name, fields, input); if(err) return { soln, err }; int session = getNextSessionId(); std::vector given(seen.size()); std::vector target(seen.size()); for(const auto& s : seen) { auto idx = fieldNames[s.first]; target[idx] = ArgType(std::get<0>(str->fields[idx]), convertPtsType(fs, str->generics, std::get<2>(str->fields[idx]), session), std::get<1>(str->fields[idx])); given[idx] = ArgType(input[s.second].name, input[s.second].value->type, input[s.second].loc); } *origParamOrder = fieldNames; return solveTypeList(fs->loc(), target, given, soln, isFnCall); } else if(auto unn = dcast(ast::UnionDefn, td)) { //* see the comment above -- same thing about infer, except we look for type_infer because for unions we know to pass it there //* (since we don't really look like a function call most of the time) if(type_infer) { if(auto gen_str = fs->typeDefnMap[type_infer]) { for(const auto& v : unn->genericVersions) { if(v.first == gen_str) { return inferPolymorphicType(fs, unn, name, problems, input, v.second.back(), /* return_infer: */ nullptr, /* type_infer: */ nullptr, isFnCall, problem_infer, origParamOrder); } } } } if(unn->cases.find(name) == unn->cases.end()) error("no variant named '%s'", name); auto uvloc = std::get<1>(unn->cases[name]); int session = getNextSessionId(); fir::Type* vty = convertPtsType(fs, unn->generics, std::get<2>(unn->cases[name]), session); // ok, then. check the type + arguments. std::vector target; if(vty->isTupleType()) { for(auto t : vty->toTupleType()->getElements()) target.push_back(ArgType("", t, uvloc)); } else if(!vty->isVoidType()) { target.push_back(ArgType("", vty, uvloc)); } auto given = zfu::map(input, [](const FnCallArgument& fca) -> ArgType { return ArgType(fca.name, fca.value->type, fca.loc); }); return solveTypeList(fs->loc(), target, given, soln, isFnCall); } else { error("no"); } } static std::pair inferPolymorphicFunction(TypecheckState* fs, ast::Parameterisable* thing, const std::string& name, const ProblemSpace_t& problems, const std::vector& input, const TypeParamMap_t& partial, fir::Type* return_infer, fir::Type* type_infer, bool isFnCall, fir::Type* problem_infer, util::hash_map* origParamOrder) { auto soln = Solution_t(partial); bool isinit = dcast(ast::InitFunctionDefn, thing) != nullptr; iceAssert(dcast(ast::FuncDefn, thing) || isinit); std::vector given; std::vector target; pts::Type* retty = 0; std::vector params; if(isinit) { auto i = dcast(ast::InitFunctionDefn, thing); params = i->params; } else { auto i = dcast(ast::FuncDefn, thing); retty = i->returnType; params = i->params; } int session = getNextSessionId(); if(!problem_infer) { target = internal::unwrapFunctionParameters(fs, problems, params, session); if(!isinit && (!isFnCall || return_infer)) { // add the return type to the fray. it doesn't have a name tho target.push_back(ArgType("", convertPtsType(fs, thing->generics, retty, session), thing->loc)); } } else { auto ift = problem_infer->toFunctionType(); zfu::foreachIdx(ift->getArgumentTypes(), [&target, ¶ms](fir::Type* ty, size_t i) { target.push_back(ArgType(params[i].name, ty, params[i].loc)); }); if(!isFnCall || return_infer) target.push_back(ArgType("", ift->getReturnType(), Location())); } if(isFnCall) { given = zfu::map(input, [](const FnCallArgument& a) -> poly::ArgType { return ArgType(a.name, a.value->type, a.loc, /* opt: */ false, /* ignoreName: */ a.ignoreName); }); if(return_infer) given.push_back(ArgType("", return_infer, Location())); *origParamOrder = resolver::misc::getNameIndexMap(params); } else { if(type_infer == 0) return { soln, nullptr }; else if(!type_infer->isFunctionType()) return { soln, SimpleError::make(fs->loc(), "invalid type '%s' inferred for '%s'", type_infer, thing->name) }; // ok, we should have it. iceAssert(type_infer->isFunctionType()); given = zfu::mapIdx(type_infer->toFunctionType()->getArgumentTypes(), [¶ms](fir::Type* t, size_t i) -> ArgType { return ArgType(params[i].name, t, params[i].loc); }) + ArgType("", type_infer->toFunctionType()->getReturnType(), thing->loc); } return solveTypeList(fs->loc(), target, given, soln, isFnCall); } std::pair inferTypesForPolymorph(TypecheckState* fs, ast::Parameterisable* thing, const std::string& name, const ProblemSpace_t& problems, const std::vector& input, const TypeParamMap_t& partial, fir::Type* return_infer, fir::Type* type_infer, bool isFnCall, fir::Type* problem_infer, util::hash_map* origParamOrder) { if(auto td = dcast(ast::TypeDefn, thing)) { return inferPolymorphicType(fs, td, name, problems, input, partial, return_infer, type_infer, isFnCall, problem_infer, origParamOrder); } else if(dcast(ast::FuncDefn, thing) || dcast(ast::InitFunctionDefn, thing)) { return inferPolymorphicFunction(fs, thing, name, problems, input, partial, return_infer, type_infer, isFnCall, problem_infer, origParamOrder); } else { iceAssert(thing); return std::make_pair(Solution_t(partial), SimpleError::make(thing->loc, "unable to infer type for unsupported entity '%s'", thing->getKind()) ); } } } } } ================================================ FILE: source/typecheck/polymorph/instantiator.cpp ================================================ // instantiator.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "sst.h" #include "ir/type.h" #include "typecheck.h" #include "polymorph.h" #include "resolver.h" namespace sst { namespace poly { namespace internal { static SimpleError* complainAboutMissingSolutions(const Location& l, ast::Parameterisable* thing, const std::vector& missing) { auto strs = zfu::map(missing, [](fir::PolyPlaceholderType* p) -> std::string { return p->str().substr(1); }); auto mstr = util::listToEnglish(strs); return SimpleError::make(l, "type %s %s could not be inferred", zfu::plural("parameter", strs.size()), mstr); } std::vector getMissingSolutions(const ProblemSpace_t& needed, const TypeParamMap_t& solution, bool allowPlaceholders) { std::vector missing; for(const auto& [ name, constr ] : needed) { (void) constr; if(auto it = solution.find(name); it == solution.end()) missing.push_back(name); else if(!allowPlaceholders && it->second->containsPlaceholders()) missing.push_back(name); } return missing; } std::pair solvePolymorphWithPlaceholders(TypecheckState* fs, ast::Parameterisable* thing, const std::string& name, const TypeParamMap_t& partial) { TypeParamMap_t copy = partial; int session = getNextSessionId(); for(const auto& p : thing->generics) { if(copy.find(p.first) == copy.end()) copy[p.first] = fir::PolyPlaceholderType::get(p.first, session); } return attemptToInstantiatePolymorph(fs, thing, name, copy, /* return_infer: */ 0, /* type_infer: */ 0, /* isFnCall: */ false, /* args: */ { }, /* fillplaceholders: */ false); } } std::pair attemptToInstantiatePolymorph(TypecheckState* fs, ast::Parameterisable* thing, const std::string& name, const TypeParamMap_t& _gmaps, fir::Type* return_infer, fir::Type* type_infer, bool isFnCall, std::vector* args, bool fillplaceholders, fir::Type* problem_infer) { if(!isFnCall && type_infer == 0 && fillplaceholders) return internal::solvePolymorphWithPlaceholders(fs, thing, name, _gmaps); // used below. util::hash_map origParamOrder; auto [ soln, err ] = internal::inferTypesForPolymorph(fs, thing, name, thing->generics, *args, _gmaps, return_infer, type_infer, isFnCall, problem_infer, &origParamOrder); if(err) return { TCResult(err), soln }; if(auto d = fullyInstantiatePolymorph(fs, thing, soln.solutions); d.isDefn()) { if(isFnCall) { // if(auto missing = internal::getMissingSolutions(thing->generics, soln.solutions, /* allowPlaceholders: */ false); missing.size() > 0) if(auto missing = d.defn()->type->getContainedPlaceholders(); missing.size() > 0) { auto se = SpanError::make(internal::complainAboutMissingSolutions(thing->loc, thing, missing)); return std::make_pair( TCResult(err->append(se)->append(SimpleError::make(fs->loc(), "partial solution: %s", zfu::listToString(zfu::map(soln.solutions, [](const std::pair& p) -> std::string { return strprintf("%s = %s", p.first, p.second); }), [](const std::string& s) -> std::string { return s; } )))), soln ); } else { size_t counter = 0; for(auto& arg : *args) { if(arg.value->type->containsPlaceholders() && arg.orig) { //! ACHTUNG ! /* * note * the implication here is that by calling 'inferTypesForPolymorph', which itself calls 'solveTypeList', we will have weeded out all of the function candidates that don't match (ie. overload distance == -1) therefore, we can operate under the assumption that the _parameter_ type of the function will be fully substituted and not have any placeholders, and that it will be a valid infer target for the _argument_. using the newly-gained arg_infer information, we can re-typecheck the argument with concrete types. - zhiayang - 06/10/18/2318 */ auto arg_infer = d.defn()->type->toFunctionType()->getArgumentN(arg.name.empty() ? counter : origParamOrder[arg.name]); auto tc = arg.orig->typecheck(fs, arg_infer); arg.value = tc.expr(); } counter += 1; } } } return std::make_pair(TCResult(d.defn()), soln); } else { iceAssert(d.isError()); return std::make_pair(TCResult(d.error()), soln); } } //* gets an generic type in the AST form and returns a concrete SST node from it, given the mappings. TCResult fullyInstantiatePolymorph(TypecheckState* fs, ast::Parameterisable* thing, const TypeParamMap_t& mappings) { iceAssert(thing); // iceAssert(!thing->generics.empty()); // try to see if we already have a generic version. if(auto [ found, def ] = thing->checkForExistingDeclaration(fs, mappings); found && def) return TCResult(def); fs->pushGenericContext(); defer(fs->popGenericContext()); for(auto map : mappings) { int ptrs = 0; { auto t = map.second; while(t->isPointerType()) t = t->getPointerElementType(), ptrs++; } if(auto it = std::find_if(thing->generics.begin(), thing->generics.end(), [&map](const auto& p) -> bool { return map.first == p.first; }); it != thing->generics.end() && ptrs < it->second.pointerDegree) { return TCResult( SimpleError::make(fs->loc(), "cannot map type '%s' to type parameter '%s' in instantiation of generic type '%s'", map.second, map.first, thing->name)->append( SimpleError::make(MsgType::Note, thing->loc, "replacement type has pointer degree %d, which is less than the required %d", ptrs, it->second.pointerDegree) ) ); } // TODO: check if the type conforms to the protocols specified. //* check if it satisfies the protocols. // ok, push the thing. fs->addGenericMapping(map.first, map.second); } fir::Type* self_infer = 0; if(thing->parentType) { // instantiate that as well, I guess. auto res = fullyInstantiatePolymorph(fs, thing->parentType, /* mappings */ {}); if(res.isError()) return TCResult(res); self_infer = res.defn()->type; } if(auto missing = internal::getMissingSolutions(thing->generics, mappings, true); missing.size() > 0) { auto mstr = util::listToEnglish(missing); return TCResult(SimpleError::make(fs->loc(), "type %s %s could not be inferred", zfu::plural("parameter", missing.size()), mstr)); } return thing->typecheck(fs, self_infer, mappings); } } } ================================================ FILE: source/typecheck/polymorph/misc.cpp ================================================ // misc.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "pts.h" #include "ast.h" #include "ir/type.h" #include "typecheck.h" #include "errors.h" #include "polymorph.h" namespace sst { namespace poly { namespace internal { static int polySessionId = 0; int getNextSessionId() { return polySessionId++; } fir::Type* mergeNumberTypes(fir::Type* a, fir::Type* b) { if(a->isConstantNumberType() && b->isConstantNumberType()) { return fir::unifyConstantTypes(a->toConstantNumberType(), b->toConstantNumberType()); } else if(a->isFloatingPointType() && b->isIntegerType()) { return a; } else if(a->isIntegerType() && b->isFloatingPointType()) { return b; } else { if(a->getBitWidth() > b->getBitWidth()) return a; else return b; } } fir::Type* convertPtsType(TypecheckState* fs, const ProblemSpace_t& problems, pts::Type* input, int polysession) { fir::Type* fty = 0; auto [ _ty, trfs ] = decomposeIntoTransforms(input); pts::Type* ty = _ty; if(ty->isNamedType()) { fty = fs->convertParserTypeToFIR(ty, true); if(!fty && (std::find_if(problems.begin(), problems.end(), [ty](const auto& a) -> bool { return ty->toNamedType()->name == a.first; }) != problems.end())) { fty = fir::PolyPlaceholderType::get(ty->toNamedType()->name, polysession); } if(!fty) error("failed to find type '%s'", input->str()); } else if(ty->isTupleType()) { fty = fir::TupleType::get(convertPtsTypeList(fs, problems, ty->toTupleType()->types, polysession)); } else if(ty->isFunctionType()) { fty = fir::FunctionType::get(convertPtsTypeList(fs, problems, ty->toFunctionType()->argTypes, polysession), convertPtsType(fs, problems, ty->toFunctionType()->returnType, polysession)); } else { error("unsupported pts type '%s'", ty->str()); } return applyTransforms(fty, trfs); } std::vector convertPtsTypeList(TypecheckState* fs, const ProblemSpace_t& problems, const std::vector& input, int polysession) { // mm, smells functional. return zfu::map(input, [fs, problems, polysession](pts::Type* pt) -> fir::Type* { return convertPtsType(fs, problems, pt, polysession); }); } std::vector unwrapFunctionParameters(TypecheckState* fs, const ProblemSpace_t& problems, const std::vector& args, int polysession) { return zfu::mapIdx(convertPtsTypeList(fs, problems, zfu::map(args, [](const ast::FuncDefn::Param& a) -> pts::Type* { return a.type; } ), polysession), [args](fir::Type* t, size_t idx) -> ArgType { return ArgType(args[idx].name, t, args[idx].loc); }); } } } std::vector TypecheckState::getGenericContextStack() { return this->genericContextStack; } void TypecheckState::pushGenericContext() { this->genericContextStack.push_back({ }); } void TypecheckState::addGenericMapping(const std::string& name, fir::Type* ty) { iceAssert(this->genericContextStack.size() > 0); if(auto it = this->genericContextStack.back().find(name); it != this->genericContextStack.back().end()) error(this->loc(), "mapping for type parameter '%s' already exists in current context (is currently '%s')", name, it->second); this->genericContextStack.back()[name] = ty; } void TypecheckState::removeGenericMapping(const std::string& name) { iceAssert(this->genericContextStack.size() > 0); if(auto it = this->genericContextStack.back().find(name); it == this->genericContextStack.back().end()) error(this->loc(), "no mapping for type parameter '%s' exists in current context, cannot remove", name); else this->genericContextStack.back().erase(it); } void TypecheckState::popGenericContext() { iceAssert(this->genericContextStack.size() > 0); this->genericContextStack.pop_back(); } fir::Type* TypecheckState::findGenericMapping(const std::string& name, bool allowFail) { // look upwards. for(auto it = this->genericContextStack.rbegin(); it != this->genericContextStack.rend(); it++) if(auto iit = it->find(name); iit != it->end()) return iit->second; if(allowFail) return 0; else error(this->loc(), "no mapping for type parameter '%s'", name); } } //* helper method that abstracts away the common error-checking std::pair ast::Parameterisable::checkForExistingDeclaration(sst::TypecheckState* fs, const TypeParamMap_t& gmaps) { //! ACHTUNG ! //* IMPORTANT * /* ? the reason we match the *ENTIRE* generic context stack when checking for an existing definition is because of nesting. * if we only checked the current map, then for methods of generic types and/or nested, non-generic types inside generic types, * we'd match an existing definition even though all the generic types are probably completely different. * so, pretty much the only way to make sure we're absolutely certain it's the same context is to compare the entire type stack. ? given that a given definition cannot 'move' to another scope, there cannot be circumstances where we can (by chance or otherwise) ? be typechecking the current definition in another, completely different context, and somehow mistake it for our own -- even if all ? the generic types match in the stack. * note: bug fix: what we should really be checking for is that the stored generic map is a strict child (ie. the last N elements match * our stored state, while the preceding ones don't matter). (this is why we use reverse iterators for std::equal) * note: bug fix of the bug fix: we should be checking whether our current state is a child of the stored state, instead of the * other way around. probably. */ { auto doRootsMatch = [](const std::vector& expected, const std::vector& given) -> bool { if(given.size() > expected.size()) return false; //* reverse iterators return std::equal(given.rbegin(), given.rend(), expected.rbegin()); }; auto currentGCS = fs->getGenericContextStack(); if(!gmaps.empty()) currentGCS.push_back(gmaps); for(const auto& gv : this->genericVersions) { //* note!! Defn::type can be null for enums -- we need to find a way to prevent this!! // TODO: prevent this!! // TODO: prevent this!! // TODO: prevent this!! // TODO: prevent this!! if(gv.first->type && !gv.first->type->containsPlaceholders() && doRootsMatch(gv.second, currentGCS)) return { true, gv.first }; } if(this->generics.size() > 0 && gmaps.empty()) { if(const auto& tys = fs->stree->unresolvedGenericDefs[this->name]; std::find(tys.begin(), tys.end(), this) == tys.end()) fs->stree->unresolvedGenericDefs[this->name].push_back(this); return { false, 0 }; } else { //? note: if we call with an empty map, then this is just a non-generic type/function/thing. Even for such things, //? the genericVersions list will have 1 entry which is just the type itself. return { true, 0 }; } } } std::string PolyArgMapping_t::print() const { std::string ret; for(const auto& m : this->maps) { ret += ", "; if(!m.name.empty()) ret += strprintf("%s: ", m.name); ret += m.type->str(); } if(!ret.empty()) ret = ret.erase(0, 2); return ret; } ================================================ FILE: source/typecheck/polymorph/solver.cpp ================================================ // solver.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "pts.h" #include "ast.h" #include "sst.h" #include "errors.h" #include "ir/type.h" #include "typecheck.h" #include "polymorph.h" namespace sst { namespace poly { static ErrorMsg* solveSingleTypeList(Solution_t* soln, const Location& callLoc, const std::vector& target, const std::vector& given, bool isFnCall); static ErrorMsg* solveSingleType(Solution_t* soln, const fir::LocatedType& target, const fir::LocatedType& given) { auto tgt = target.type; auto gvn = given.type; // if we're just looking at normal types, then just add the cost. if(!tgt->containsPlaceholders() && !gvn->containsPlaceholders()) { int dist = fir::getCastDistance(gvn, tgt); if(dist >= 0) { soln->distance += dist; return nullptr; } else { soln->distance = -1; return SimpleError::make(given.loc, "no valid cast from given type '%s' to target type '%s'", gvn, tgt); } } else { // limit decomposition of the given types by the number of transforms on the target type. auto [ tt, ttrfs ] = internal::decomposeIntoTransforms(tgt, static_cast(-1)); auto [ gt, gtrfs ] = internal::decomposeIntoTransforms(gvn, ttrfs.size()); // if(ttrfs != gtrfs) // hmm??? // substitute if possible. if(auto _gt = soln->substitute(gt); _gt != gt) gt = _gt; // check what kind of monster we're dealing with. if(tt->isPolyPlaceholderType()) { // see if there's a match. auto ptt = tt->toPolyPlaceholderType(); if(auto ltt = soln->getSolution(ptt->getName()); ltt != 0) { // check for conflict. if(!ltt->isPolyPlaceholderType() && !gt->isPolyPlaceholderType()) { if(ltt->isConstantNumberType() || gt->isConstantNumberType()) { gt = internal::mergeNumberTypes(ltt, gt); if(gt != ltt) soln->addSolution(ptt->getName(), fir::LocatedType(gt, given.loc)); } else if(ltt != gt) { if(int d = fir::getCastDistance(gt, ltt); d >= 0) { soln->distance += d; } else { return SimpleError::make(given.loc, "conflicting solutions for type parameter '%s': previous: '%s', current: '%s'", ptt->getName(), ltt->str(), gvn); } } } else if(ltt->isPolyPlaceholderType() && !gt->isPolyPlaceholderType()) { soln->addSubstitution(ltt, gt); } else if(!ltt->isPolyPlaceholderType() && gt->isPolyPlaceholderType()) { soln->addSubstitution(gt, ltt); } else if(ltt->isPolyPlaceholderType() && gt->isPolyPlaceholderType()) { warn("what???? '%s' and '%s' are both poly??", ltt->str(), gt); } } else { // debuglogln("solved %s = %s", ptt->getName(), gt); soln->addSolution(ptt->getName(), fir::LocatedType(gt, given.loc)); } } else if(tt->isFunctionType() || tt->isTupleType()) { // make sure they're the same 'kind' of type first. if(tt->isFunctionType() != gt->isFunctionType() || tt->isTupleType() != gt->isTupleType()) return SimpleError::make(given.loc, "no valid conversion from given type '%s' to target type '%s'", gt, tt); std::vector problem; std::vector input; if(gt->isFunctionType()) { input = zfu::map(gt->toFunctionType()->getArgumentTypes(), [given](fir::Type* t) -> ArgType { return ArgType("", t, given.loc); }) + ArgType("", gt->toFunctionType()->getReturnType(), given.loc); problem = zfu::map(tt->toFunctionType()->getArgumentTypes(), [target](fir::Type* t) -> ArgType { return ArgType("", t, target.loc); }) + ArgType("", tt->toFunctionType()->getReturnType(), target.loc); } else { iceAssert(gt->isTupleType()); input = zfu::map(gt->toTupleType()->getElements(), [given](fir::Type* t) -> ArgType { return ArgType("", t, given.loc); }); problem = zfu::map(tt->toTupleType()->getElements(), [target](fir::Type* t) -> ArgType { return ArgType("", t, target.loc); }); } // for recursive solving, we're never a function call. // related: so, firstOptionalArgument is always -1 in these cases. return solveSingleTypeList(soln, given.loc, problem, input, /* isFnCall: */ false); } else { error("'%s' not supported", tt); } } return nullptr; } static ErrorMsg* solveSingleTypeList(Solution_t* soln, const Location& callLoc, const std::vector& target, const std::vector& given, bool isFnCall) { bool fvararg = (isFnCall && target.size() > 0 && target.back()->isVariadicArrayType()); util::hash_map targetnames; // either we have all names or no names for the target! if(target.size() > 0 && target[0].name != "") { zfu::foreachIdx(target, [&targetnames](const ArgType& t, size_t i) { targetnames[t.name] = i; }); } std::set unsolvedtargets; zfu::foreachIdx(target, [&unsolvedtargets, &target, fvararg](const ArgType& a, size_t i) { // if it's optional, we don't mark it as 'unsolved'. if((!fvararg || i + 1 != target.size()) && !a.optional) unsolvedtargets.insert(i); }); // record which optionals we passed, for a better error message. std::set providedOptionals; size_t last_arg = std::min(target.size() + (fvararg ? -1 : 0), given.size()); // we used to do this check in the parser, but to support more edge cases (like passing varargs) // we moved it here so we can actually check stuff. bool didNames = false; size_t positionalCounter = 0; size_t varArgStart = last_arg; for(size_t i = 0; i < last_arg; i++) { const ArgType* targ = 0; // note that when we call std::set::erase(), if the key did not exist (because it was optional), // nothing will happen, which is fine. if(targetnames.size() > 0 && given[i].name != "") { if(auto it = targetnames.find(given[i].name); it != targetnames.end()) { targ = &target[it->second]; unsolvedtargets.erase(it->second); } else { return SimpleError::make(given[i].loc, "function has no parameter named '%s'", given[i].name); } /* optional arguments "don't count" as passing by name. this means that you can do this, for example: foo(x: 30, "blabla") where 'x' is an optional argument. this should be fine in terms of the rest of the compiler, because when we *declare* the function, all optional arguments must come last. this gives us a good compromise because optional arguments must still be passed by name, but we can actually have optional arguments together with variadic functions without needing to name all the arguments. */ if(!targ->optional) { if(!given[i].ignoreName) didNames = true; positionalCounter++; } else { providedOptionals.insert(given[i].name); } } else { /* we didn't pass a name. if the function is variadic, we might have wanted to pass the following argument(s) variadically. so, instead of assuming we made a mistake (like not passing the optional by name), assume we wanted to pass it to the vararg. so, `positionalCounter` counts the paramters on the declaration-side. thus, once we encounter a default value, it must mean that the rest of the parameters will be optional as well. * ie. we've passed all the positional arguments already, leaving the optional ones, which means every argument from * here onwards (including this one) must be named. since this is *not* named, we just skip straight to the varargs if * it was present. */ targ = &target[positionalCounter]; if(fvararg && targ->optional) { varArgStart = i; break; } unsolvedtargets.erase(positionalCounter); positionalCounter++; } /* TODO: not sure if there's a way to get around this, but if we have a function like this: fn foo(a: int, b: int, c: int, x: int = 9, y: int = 8, z: int = 7) { ... } then calling it wrongly like this: foo(x: 4, 1, 2, 5, z: 6, 3) results in an error at the last argument ('3') saying taht optional argument 'x' must be passed by name. the problem is that we can't really tell what argument you wanted to pass; after seeing '1', '2', and '5', the positionalCounter now points to the 4th argument, 'x'. even though you already passed x prior, we don't really know that? and we assume you wanted to pass x (again) */ if(given[i].name.empty()) { if(didNames) return SimpleError::make(given[i].loc, "positional arguments cannot appear after named arguments"); else if(targ->optional) { std::string probablyIntendedArgumentName; for(const auto& a : target) { if(!a.optional) continue; if(auto it = providedOptionals.find(a.name); it == providedOptionals.end()) { probablyIntendedArgumentName = a.name; break; } }; if(probablyIntendedArgumentName.empty()) { //* this shouldn't happen, because we only get here if we're not variadic, but if we weren't //* variadic, then we would've errored out if the argument count was wrong to begin with. return SimpleError::make(given[i].loc, "extraneous argument without corresponding parameter"); } else { return SimpleError::make(given[i].loc, "optional argument '%s' must be passed by name", probablyIntendedArgumentName); } } } iceAssert(targ); auto err = solveSingleType(soln, targ->toFLT(), given[i].toFLT()); if(err != nullptr) return err; // possibly increase solution completion by re-substituting with new information soln->resubstituteIntoSolutions(); } if(unsolvedtargets.size() > 0 || (!fvararg && given.size() > target.size())) { if(targetnames.empty() || given.size() > target.size()) { return SimpleError::make(callLoc, "expected %d %s, but %d %s provided", target.size(), zfu::plural("argument", target.size()), given.size(), given.size() == 1 ? "was" : "were"); } else { std::vector missings; for(const auto& us : unsolvedtargets) missings.push_back(target[us].name); auto s = util::listToEnglish(missings, /* quote: */ true); return SimpleError::make(callLoc, "missing %s for %s %s", zfu::plural("argument", missings.size()), zfu::plural("parameter", missings.size()), s); } } // solve the variadic part. if(fvararg) { // check for forwarding first. if(given.size() == target.size() && given.back()->isVariadicArrayType()) { auto copy = *soln; // ok, if we fulfil all the conditions to forward, then we forward. auto err = solveSingleType(©, target.back().toFLT(), given.back().toFLT()); if(err == nullptr) { iceAssert(copy.distance >= 0); *soln = copy; // ok, things should be solved, and we will forward. return nullptr; } } //* note: the reason we put this outside an 'else' is so that, in the event we're unable to solve //* for the forwarding case for whatever reason, we will treat it as an argument-passing case. // get the supposed type of the thing. auto varty = target.back()->toArraySliceType()->getArrayElementType(); auto ltvarty = fir::LocatedType(varty, target.back().loc); for(size_t i = varArgStart; i < given.size(); i++) { auto err = solveSingleType(soln, ltvarty, given[i].toFLT()); if(err) return err->append(SimpleError::make(MsgType::Note, target.back().loc, "in argument of variadic parameter")); } // ok, everything should be good?? return nullptr; } return nullptr; } std::pair solveTypeList(const Location& callLoc, const std::vector& target, const std::vector& given, const Solution_t& partial, bool isFnCall) { Solution_t prevSoln = partial; std::vector tosolve; for(auto t : target) tosolve = tosolve + t->getContainedPlaceholders(); auto checkFinished = [&tosolve](const Solution_t& soln) -> bool { for(auto t : tosolve) { if(!soln.hasSolution(t->getName())) return false; } return true; }; while(true) { //* note!! we reset the distance here, because we will always loop through every argument. //* if we didn't reset the distance, it would just keep increasing to infinity (and overflow) auto soln = prevSoln; soln.distance = 0; auto errs = solveSingleTypeList(&soln, callLoc, target, given, isFnCall); if(errs) return { soln, errs }; if(soln == prevSoln) { break; } else if(checkFinished(soln)) { prevSoln = soln; break; } else { prevSoln = soln; } } for(auto& pair : prevSoln.solutions) { if(pair.second->isConstantNumberType()) pair.second = fir::getBestFitTypeForConstant(pair.second->toConstantNumberType()); } return { prevSoln, nullptr }; } } } ================================================ FILE: source/typecheck/polymorph/transforms.cpp ================================================ // transforms.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "pts.h" #include "ir/type.h" #include "errors.h" #include "polymorph.h" namespace sst { namespace poly { void Solution_t::addSolution(const std::string& x, const fir::LocatedType& y) { this->solutions[x] = y.type; } void Solution_t::addSubstitution(fir::Type* x, fir::Type* y) { if(auto it = this->substitutions.find(x); it != this->substitutions.end()) { if(it->second != y) error("conflicting substitutions for '%s': '%s' and '%s'", x, y, it->second); debuglogln("substitution: '%s' -> '%s'", x, y); } this->substitutions[x] = y; } bool Solution_t::hasSolution(const std::string& n) const { return this->solutions.find(n) != this->solutions.end(); } fir::LocatedType Solution_t::getSolution(const std::string& n) const { if(auto it = this->solutions.find(n); it != this->solutions.end()) return fir::LocatedType(it->second); else return fir::LocatedType(0); } fir::Type* Solution_t::substitute(fir::Type* x) const { if(auto it = this->substitutions.find(x); it != this->substitutions.end()) return it->second; else return x; } void Solution_t::resubstituteIntoSolutions() { // iterate through everything for(auto& [ n, t ] : this->solutions) t = this->substitute(t); } bool Solution_t::operator == (const Solution_t& other) const { return other.distance == this->distance && other.solutions == this->solutions && other.substitutions == this->substitutions; } bool Solution_t::operator != (const Solution_t& other) const { return !(other == *this); } namespace internal { std::pair> decomposeIntoTransforms(fir::Type* t, size_t max) { std::vector ret; for(size_t i = 0; i < max; i++) { if(t->isDynamicArrayType()) { ret.push_back(Trf(TrfType::DynamicArray)); t = t->getArrayElementType(); } else if(t->isArraySliceType()) { if(t->isVariadicArrayType()) ret.push_back(Trf(TrfType::VariadicArray)); else ret.push_back(Trf(TrfType::Slice, t->toArraySliceType()->isMutable())); t = t->getArrayElementType(); } else if(t->isArrayType()) { ret.push_back(Trf(TrfType::FixedArray, t->toArrayType()->getArraySize())); t = t->getArrayElementType(); } else if(t->isPointerType()) { ret.push_back(Trf(TrfType::Pointer, t->isMutablePointer())); t = t->getPointerElementType(); } else { break; } } return { t, ret }; } std::pair> decomposeIntoTransforms(pts::Type* t) { std::vector ret; while(true) { if(t->isDynamicArrayType()) { ret.push_back(Trf(TrfType::DynamicArray)); t = t->toDynamicArrayType()->base; } else if(t->isArraySliceType()) { ret.push_back(Trf(TrfType::Slice, t->toArraySliceType()->mut)); t = t->toArraySliceType()->base; } else if(t->isFixedArrayType()) { ret.push_back(Trf(TrfType::FixedArray, t->toFixedArrayType()->size)); t = t->toFixedArrayType()->base; } else if(t->isPointerType()) { ret.push_back(Trf(TrfType::Pointer, t->toPointerType()->isMutable)); t = t->toPointerType()->base; } else if(t->isVariadicArrayType()) { ret.push_back(Trf(TrfType::VariadicArray)); t = t->toVariadicArrayType()->base; } else { break; } } return { t, ret }; } fir::Type* applyTransforms(fir::Type* base, const std::vector& trfs) { for(auto it = trfs.rbegin(); it != trfs.rend(); it++) { switch(it->type) { case TrfType::None: break; case TrfType::Slice: base = fir::ArraySliceType::get(base, static_cast(it->data)); break; case TrfType::Pointer: base = base->getPointerTo(); if(static_cast(it->data)) base = base->getMutablePointerVersion(); break; case TrfType::FixedArray: base = fir::ArrayType::get(base, it->data); break; case TrfType::DynamicArray: base = fir::DynamicArrayType::get(base); break; case TrfType::VariadicArray: base = fir::ArraySliceType::getVariadic(base); break; default: error("unsupported transformation '%d'", static_cast(it->type)); } } return base; } } } } ================================================ FILE: source/typecheck/ranges.cpp ================================================ // ranges.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "errors.h" #include "typecheck.h" #include "ir/type.h" #include "memorypool.h" TCResult ast::RangeExpr::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); auto ret = util::pool(this->loc, fir::RangeType::get()); ret->halfOpen = this->halfOpen; ret->start = this->start->typecheck(fs, fir::Type::getNativeWord()).expr(); if(!ret->start->type->isIntegerType()) error(ret->start, "expected integer type in range expression (start), found '%s' instead", ret->start->type); ret->end = this->end->typecheck(fs, fir::Type::getNativeWord()).expr(); if(!ret->end->type->isIntegerType()) error(ret->end, "expected integer type in range expression (end), found '%s' instead", ret->end->type); if(this->step) { ret->step = this->step->typecheck(fs, fir::Type::getNativeWord()).expr(); if(!ret->step->type->isIntegerType()) error(ret->step, "expected integer type in range expression (step), found '%s' instead", ret->step->type); } return TCResult(ret); } ================================================ FILE: source/typecheck/resolver/driver.cpp ================================================ // call.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "pts.h" #include "ast.h" #include "errors.h" #include "typecheck.h" #include "polymorph.h" #include "resolver.h" #include "ir/type.h" #include namespace sst { namespace resolver { TCResult resolveFunctionCallFromCandidates(TypecheckState* fs, const Location& callLoc, const std::vector& cands, std::vector* args, const PolyArgMapping_t& gmaps, bool allowImplicitSelf) { auto cds = zfu::map(cands, [&args](auto c) -> std::pair> { return { c, *args }; }); auto [ ret, new_args ] = resolver::internal::resolveFunctionCallFromCandidates(fs, fs->loc(), cds, gmaps, allowImplicitSelf, nullptr); *args = new_args; return ret; } TCResult resolveFunctionCall(TypecheckState* fs, const Location& callLoc, const std::string& name, std::vector* arguments, const PolyArgMapping_t& gmaps, bool travUp, fir::Type* return_infer) { StateTree* tree = fs->stree; //* the purpose of this 'didVar' flag (because I was fucking confused reading this) //* is so we only consider the innermost (ie. most local) variable, because variables don't participate in overloading. //! ACHTUNG ! // TODO: do we even need this didVar nonsense? variables don't overload yes, but we can't even define more than one // TODO: variable in a scope with the same name. if we find something with a matching name we quit immediately, so there // TODO: shouldn't be a point in having 'didVar'!! // TODO: - zhiayang, 28/10/18 //? I can't find any information about this behaviour in languages other than C++, because we need to have a certain set of //? features for it to manifest -- 1. user-defined, explicit namespaces; 2. function overloading. //* how it works in C++, and for now also in Flax, is that once we match *any* names in the current scope, we stop searching upwards //* -- even if it means we will throw an error because of mismatched arguments or whatever. // bool didVar = false; bool didGeneric = false; std::vector> fails; std::vector, poly::Solution_t>> fns; while(tree) { { auto defs = tree->getDefinitionsWithName(name); for(auto d : defs) fns.push_back({ d, *arguments, poly::Solution_t() }); } if(auto gdefs = tree->getUnresolvedGenericDefnsWithName(name); gdefs.size() > 0) { didGeneric = true; auto argcopy = *arguments; auto pots = poly::findPolymorphReferences(fs, name, gdefs, gmaps, /* return_infer: */ return_infer, /* type_infer: */ 0, /* isFnCall: */ true, &argcopy); for(const auto& pot : pots) { if(!pot.res.isDefn()) { iceAssert(pot.res.isError()); fails.push_back({ pot.thing, pot.res.error() }); } else { auto def = pot.res.defn(); if(def->type->containsPlaceholders()) error("wtf??? '%s'", def->type); // make sure we didn't already find this in the non-generic search //? (can happen when we recursively call a generic function!) if(auto it = std::find_if(fns.begin(), fns.end(), [def](const auto& tup) -> bool { return std::get<0>(tup) == def; }); it != fns.end()) { continue; } auto sln = pot.soln; // ! ACHTUNG ! // insert a hefty penalty for using a polymorphic function! // this doesn't disallow polymorphic functions from participating in // overloading, but this makes our resolver prefer non-generic functions. sln.distance += 10; fns.push_back({ def, argcopy, sln }); } } } if(travUp && fns.empty()) tree = tree->parent; else break; } if(fns.empty()) { if(!didGeneric) { auto top = fs->stree; while(top && top->parent) top = top->parent; return TCResult(SimpleError::make(fs->loc(), "no function named '%s' in the current scope", name)); } else { auto err = createErrorFromFailedCandidates(fs, callLoc, name, *arguments, fails); return TCResult(err); } } std::vector>> cands; for(const auto& [ def, args, soln ] : fns) { auto ts = args; // copy it. if(dcast(FunctionDecl, def) || dcast(TypeDefn, def)) { cands.push_back({ def, ts }); } else if(dcast(VarDefn, def) && def->type->isFunctionType() /* && !didVar */) { cands.push_back({ def, ts }); // didVar = true; } else { return TCResult( SimpleError::make(fs->loc(), "'%s' cannot be called as a function; it was defined with type '%s'", name, def->type)->append(SimpleError::make(def->loc, "the definition was here:")) ); } } auto [ res, new_args ] = resolver::internal::resolveFunctionCallFromCandidates(fs, fs->loc(), cands, gmaps, travUp, return_infer); if(res.isDefn()) *arguments = new_args; return res; } TCResult resolveConstructorCall(TypecheckState* fs, const Location& callLoc, TypeDefn* typedf, const std::vector& arguments, const PolyArgMapping_t& pams) { //! ACHTUNG: DO NOT REARRANGE ! //* NOTE: ClassDefn inherits from StructDefn * if(auto cls = dcast(ClassDefn, typedf)) { // class initialisers must be called with named arguments only. for(const auto& arg : arguments) { if(arg.name.empty()) { return TCResult(SimpleError::make(arg.loc, "arguments to class initialisers (for class '%s' here) must be named", cls->id.name)); } } auto copy = arguments; //! SELF HANDLING (INSERTION) (CONSTRUCTOR CALL) copy.insert(copy.begin(), FnCallArgument::make(cls->loc, "this", cls->type->getMutablePointerTo(), /* ignoreName: */ true)); auto copy1 = copy; auto cand = resolveFunctionCallFromCandidates(fs, callLoc, zfu::map(cls->initialisers, [](auto e) -> auto { return dcast(sst::Defn, e); }), ©, pams, true); // TODO: support re-eval of constructor args! // TODO: support re-eval of constructor args! // TODO: support re-eval of constructor args! if(cand.isError()) { cand.error()->prepend(SimpleError::make(fs->loc(), "failed to find matching initialiser for class '%s':", cls->id.name)); return TCResult(cand.error()); } if(copy1 != copy) error(fs->loc(), "args changed for constructor call -- fixme!!!"); return TCResult(cand); } else if(auto str = dcast(StructDefn, typedf)) { std::vector fieldNames; for(auto f : str->fields) fieldNames.push_back(f->id.name); auto [ seen, err ] = resolver::verifyStructConstructorArguments(fs->loc(), str->id.name, fieldNames, arguments); if(err != nullptr) { return TCResult(err); } else { auto seencopy = seen; std::vector target = zfu::filterMap(str->fields, [&seencopy](sst::StructFieldDefn* f) -> bool { return seencopy.find(f->id.name) != seencopy.end(); }, [](sst::StructFieldDefn* f) -> FnParam { return FnParam(f->loc, f->id.name, f->type); }); auto args = zfu::map(arguments, [](const FnCallArgument& a) -> poly::ArgType { return poly::ArgType(a.name, a.value->type, a.loc); }); auto [ soln, err ] = poly::solveTypeList(fs->loc(), zfu::map(target, [](const FnParam& f) -> poly::ArgType { return poly::ArgType(f.name, f.type, f.loc, f.defaultVal != 0); }), args, poly::Solution_t(), /* isFnCall: */ true); // in actual fact we just return the thing here. sigh. if(err != nullptr) return TCResult(err); else return TCResult(str); } } else if(auto uvd = dcast(sst::UnionVariantDefn, typedf)) { // TODO: support re-eval of constructor args! // TODO: support re-eval of constructor args! // TODO: support re-eval of constructor args! auto copy = arguments; auto ret = resolver::resolveAndInstantiatePolymorphicUnion(fs, uvd, ©, /* type_infer: */ nullptr, /* isFnCall: */ true); if(copy != arguments) error(fs->loc(), "args changed for constructor call -- fixme!!!"); return ret; } else if(auto rud = dcast(sst::RawUnionDefn, typedf)) { return TCResult(SimpleError::make(fs->loc(), "constructors are not defined for raw unions") ->append(SimpleError::make(MsgType::Note, rud->loc, "type was defined here:")) ); } else { return TCResult( SimpleError::make(fs->loc(), "unsupported constructor call on type '%s'", typedf->id.name) ->append(SimpleError::make(MsgType::Note, typedf->loc, "type was defined here:")) ); } } } fir::Type* TypecheckState::checkIsBuiltinConstructorCall(const std::string& name, const std::vector& arguments) { if(auto type = fir::Type::fromBuiltin(name)) { for(const auto& a : arguments) { if(!a.name.empty()) error(a.loc, "builtin type initialisers do not accept named arguments"); } // all builtin types can be zero-initialised. if(arguments.empty()) { return type; } else if(arguments.size() == 1) { if(int d = getCastDistance(arguments[0].value->type, type); d >= 0 || (type->isStringType() && arguments[0].value->type->isCharSliceType())) { return type; } else { error(arguments[0].loc, "type mismatch in initialiser call to builtin type '%s', found type '%s' instead", type, arguments[0].value->type); } } else { if(type->isStringType()) { // either from a slice, or from a ptr + len if(arguments.size() == 1) { if(!arguments[0].value->type->isCharSliceType()) { error(arguments[0].loc, "single argument to string initialiser must be a slice of char, aka '%s', found '%s' instead", fir::Type::getCharSlice(false), arguments[0].value->type); } return type; } else if(arguments.size() == 2) { if(auto t1 = arguments[0].value->type; (t1 != fir::Type::getInt8Ptr() && t1 != fir::Type::getMutInt8Ptr())) { error(arguments[0].loc, "first argument to two-arg string initialiser (data pointer) must be '%s' or '%s', found '%s' instead", fir::Type::getInt8Ptr(), fir::Type::getMutInt8Ptr(), t1); } else if(auto t2 = arguments[1].value->type; fir::getCastDistance(t2, fir::Type::getNativeWord()) < 0) { error(arguments[0].loc, "second argument to two-arg string initialiser (length) must be '%s', found '%s' instead", fir::Type::getNativeWord(), t2); } else { return type; } } else { error(arguments[2].loc, "string initialiser only takes 1 (from slice) or 2 (from pointer+length)" " arguments, found '%d' instead", arguments.size()); } } else { error(arguments[1].loc, "builtin type '%s' cannot be initialised with more than 1 value", type); } } } return 0; } } ================================================ FILE: source/typecheck/resolver/misc.cpp ================================================ // misc.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "sst.h" #include "resolver.h" #include "polymorph.h" #include "typecheck.h" #include "ir/type.h" namespace sst { namespace resolver { namespace misc { std::pair canonicalisePolyArguments(TypecheckState* fs, ast::Parameterisable* thing, const PolyArgMapping_t& pams) { if(thing->generics.empty()) return { { }, SimpleError::make(fs->loc(), "cannot canonicalise poly arguments for non-generic (or nested) entity '%s'", thing->name) }; TypeParamMap_t ret; //? we only check if we provided more than necessary, because (1) we might have optional args in the future, and (2) we can omit args //? to infer stuff. if(thing->generics.size() < pams.maps.size()) { return { { }, SimpleError::make(fs->loc(), "mismatched number of type arguments to polymorph '%s'; expected %d, found %d instead", thing->name, thing->generics.size(), pams.maps.size()) }; } for(const auto& pam : pams.maps) { if(!pam.name.empty()) { // check if it exists. auto it = std::find_if(thing->generics.begin(), thing->generics.end(), [&pam](const std::pair& a) -> bool { return a.first == pam.name; }); if(it == thing->generics.end()) return { { }, SimpleError::make(fs->loc(), "no type parameter named '%s' in polymorph '%s'", pam.name, thing->name) }; // ok, it works. ret[pam.name] = fs->convertParserTypeToFIR(pam.type, /* allowFailure: */ false); } else { // ok, the index ought to exist. iceAssert(pam.index < thing->generics.size()); // should be simple. ret[thing->generics[pam.index].first] = fs->convertParserTypeToFIR(pam.type, /* allowFailure: */ false); } } return { ret, nullptr }; } std::vector typecheckCallArguments(TypecheckState* fs, const std::vector>& args) { return zfu::map(args, [fs](const auto& a) -> FnCallArgument { return FnCallArgument(a.second->loc, a.first, a.second->typecheck(fs).expr(), a.second); }); } } TCResult resolveAndInstantiatePolymorphicUnion(TypecheckState* fs, sst::UnionVariantDefn* uvd, std::vector* arguments, fir::Type* union_infer, bool isFnCall) { auto name = uvd->variantName; auto unn = uvd->parentUnion; iceAssert(unn); if(unn->type->containsPlaceholders()) { auto orig_unn = unn->original; iceAssert(orig_unn); auto [ res, soln ] = poly::attemptToInstantiatePolymorph(fs, orig_unn, name, /* gmaps: */ { }, /* return_infer */ nullptr, /* type_infer: */ union_infer, isFnCall, arguments, /* fillPlaceholders: */ false, /* problem_infer: */ nullptr); if(res.isError() || (res.isDefn() && res.defn()->type->containsPlaceholders())) { ErrorMsg* e = SimpleError::make(fs->loc(), "unable to infer types for union '%s' using variant '%s'", unn->id.name, name); if(res.isError()) e->append(res.error()); return TCResult(e); } // make it so unn = dcast(sst::UnionDefn, res.defn()); iceAssert(unn); // re-do it. uvd = unn->variants[name]; iceAssert(uvd); } auto vty = uvd->type->toUnionVariantType()->getInteriorType(); if(isFnCall) { std::vector target; if(vty->isTupleType()) { for(auto t : vty->toTupleType()->getElements()) target.push_back(fir::LocatedType(t, uvd->loc)); } else if(!vty->isVoidType()) { target.push_back(fir::LocatedType(vty, uvd->loc)); } auto [ dist, errs ] = resolver::computeOverloadDistance(unn->loc, target, zfu::map(*arguments, [](const FnCallArgument& fca) -> auto { return fir::LocatedType(fca.value->type, fca.loc); }), /* isCVarArg: */ false, fs->loc()); if(errs != nullptr || dist == -1) { auto x = SimpleError::make(fs->loc(), "mismatched types in construction of variant '%s' of union '%s'", name, unn->id.name); if(errs) errs->prepend(x); else errs = x; return TCResult(errs); } } return TCResult(uvd); } std::pair, ErrorMsg*> verifyStructConstructorArguments(const Location& callLoc, const std::string& name, const std::vector& fieldNames, const std::vector& arguments) { //* note that structs don't have inline member initialisers, so there's no trouble with this approach (in the codegeneration) //* of inserting missing arguments as just '0' or whatever their default value is //* in the case of classes, they will have inline initialisers, so the constructor calling must handle such things. //* but then class constructors are handled like regular functions, so it should be fine. bool useNames = false; bool firstName = true; size_t ctr = 0; util::hash_map seenNames; for(const auto& arg : arguments) { if((arg.name.empty() && useNames) || (!firstName && !useNames && !arg.name.empty())) { return { { }, SimpleError::make(arg.loc, "named arguments cannot be mixed with positional arguments in a struct constructor") }; } else if(firstName && !arg.name.empty()) { useNames = true; } if(!arg.name.empty() && std::find(fieldNames.begin(), fieldNames.end(), arg.name) == fieldNames.end()) { return { { }, SimpleError::make(arg.loc, "field '%s' does not exist in struct '%s'", arg.name, name) }; } else if(!arg.name.empty() && seenNames.find(arg.name) != seenNames.end()) { return { { }, SimpleError::make(arg.loc, "duplicate argument for field '%s' in constructor call to struct '%s'", arg.name, name) }; } firstName = false; seenNames[arg.name] = ctr; ctr += 1; } //* note: if we're doing positional args, allow only all or none. if(!useNames) { if(arguments.size() != fieldNames.size() && arguments.size() > 0) { return { { }, SimpleError::make(callLoc, "mismatched number of arguments in constructor call to type '%s'; expected %d, found %d instead", name, fieldNames.size(), arguments.size())->append( BareError::make(MsgType::Note, "all arguments are mandatory when using positional arguments") ) }; } // ok; populate 'seenNames' with all the fields, because we 'saw' them, I guess. for(size_t i = 0; i < fieldNames.size(); i++) seenNames[fieldNames[i]] = i; } return { seenNames, nullptr }; } } int getOverloadDistance(const std::vector& a, const std::vector& b) { return resolver::computeOverloadDistance(Location(), zfu::map(a, [](fir::Type* t) -> fir::LocatedType { return fir::LocatedType(t, Location()); }), zfu::map(b, [](fir::Type* t) -> fir::LocatedType { return fir::LocatedType(t, Location()); }), /* isCVarArg: */ false, Location()).first; } bool isDuplicateOverload(const std::vector& a, const std::vector& b) { return getOverloadDistance(zfu::map(a, [](const auto& p) -> auto { return p.type; }), zfu::map(b, [](const auto& p) -> auto { return p.type; })) == 0; } } ================================================ FILE: source/typecheck/resolver/resolver.cpp ================================================ // resolver.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "sst.h" #include "errors.h" #include "ir/type.h" #include "typecheck.h" #include "resolver.h" #include "polymorph.h" namespace sst { namespace resolver { std::pair computeOverloadDistance(const Location& fnLoc, const std::vector& _target, const std::vector& _args, bool cvararg, const Location& callLoc) { std::vector _input; if(cvararg) _input = zfu::take(_args, _target.size()); else _input = _args; auto input = zfu::map(_input, [](auto t) -> poly::ArgType { return poly::ArgType("", t.type, t.loc); }); auto target = zfu::map(_target, [](auto t) -> poly::ArgType { return poly::ArgType("", t.type, t.loc); }); auto [ soln, err ] = poly::solveTypeList(callLoc, target, input, poly::Solution_t(), /* isFnCall: */ true); if(err != nullptr) return { -1, err }; else return { soln.distance, nullptr }; } std::pair computeNamedOverloadDistance(const Location& fnLoc, const std::vector& target, const std::vector& _args, bool cvararg, const Location& callLoc) { std::vector input; if(cvararg) input = zfu::take(_args, target.size()); else input = _args; auto arguments = zfu::map(input, [](const FnCallArgument& a) -> poly::ArgType { return poly::ArgType(a.name, a.value->type, a.loc, /* opt: */ false, /* ignoreName: */ a.ignoreName); }); // ok, in this case we should figure out where the first optional argument lives, and pass that to // the type-list solver. it doesn't need to know what the actual value is --- when we typechecked the function, we should // have already verified the default value fits the type, and it doesn't actually change the type of the receiver. auto [ soln, err1 ] = poly::solveTypeList(callLoc, zfu::map(target, [](const FnParam& p) -> poly::ArgType { return poly::ArgType(p.name, p.type, p.loc, p.defaultVal != 0); }), arguments, poly::Solution_t(), /* isFnCall: */ true); if(err1 != nullptr) return { -1, err1 }; else return { soln.distance, nullptr }; } ErrorMsg* createErrorFromFailedCandidates(TypecheckState* fs, const Location& callLoc, const std::string& name, const std::vector& args, const std::vector>& fails) { // if we only had one candidate, there are no 'overloads' -- don't be a c++ and say stupid things. // we just directly post the error message instead. if(fails.size() == 1) { auto fail = fails.begin(); auto ret = fail->second; if(auto f = dcast(FunctionDefn, fail->first); f) { ret->append(SimpleError::make(MsgType::Note, f->loc, "function '%s' was defined here:", f->id.name)); } else if(auto v = dcast(VarDefn, fail->first); v) { ret->append(SimpleError::make(MsgType::Note, v->loc, "'%s' was defined here with type '%s':", v->id.name, v->type)); } return ret; } else { std::vector tmp = zfu::map(args, [](const FnCallArgument& p) -> auto { return p.value->type; }); auto errs = OverloadError::make(SimpleError::make(callLoc, "no overload in call to '%s' with arguments (%s) amongst %d %s", name, fir::Type::typeListToString(tmp), fails.size(), zfu::plural("candidate", fails.size()))); for(auto f : fails) { // TODO: HACK -- pass the location around more then!! // patch in the location if it's not present! if(auto se = dcast(SimpleError, f.second); se) { se->loc = f.first->loc; se->msg = "candidate unsuitable: " + se->msg; } errs->addCand(f.first, f.second); } return errs; } } namespace internal { std::pair> resolveFunctionCallFromCandidates(TypecheckState* fs, const Location& callLoc, const std::vector>>& _cands, const PolyArgMapping_t& pams, bool allowImplicitSelf, fir::Type* return_infer) { if(_cands.empty()) return { TCResult(BareError::make("no candidates")), { } }; int bestDist = INT_MAX; std::map fails; std::vector, int>> finals; auto cands = _cands; auto complainAboutExtraneousPAMs = [&fs](const std::string& kind, Defn* def, const std::string& action, bool printdef) -> ErrorMsg* { auto ret = SimpleError::make(fs->loc(), "%s '%s' cannot be %s with type arguments", kind, def->id.name, action); if(printdef) ret->append(SimpleError::make(MsgType::Note, def->loc, "function was defined here:")); return ret; }; for(const auto& [ _cand, _args ] : cands) { int dist = -1; Defn* curcandidate = _cand; std::vector replacementArgs = _args; if(auto fn = dcast(FunctionDecl, curcandidate)) { // check for placeholders -- means that we should attempt to infer the type of the parent if its a static method. //* there are some assumptions we can make -- primarily that this will always be a static method of a type. //? (a): namespaces cannot be generic. //? (b): instance methods must have an associated 'self', and you can't have a variable of generic type //! are these assumptions still valid?? 02/12/18 //! SELF HANDLING (INSERTION) (METHOD CALL) bool insertedSelf = false; if(fn->parentTypeForMethod && (replacementArgs.size() == fn->params.size() - 1)) { insertedSelf = true; // ignoreName records the fact that we are not actually passing 'self' with a name; it // is there so we do not "pass positional arguments after named arguments". replacementArgs.insert(replacementArgs.begin(), FnCallArgument::make(fn->loc, "this", fn->parentTypeForMethod->getMutablePointerTo(), /* ignoreName: */ true)); } if(fn->type->containsPlaceholders()) { if(auto fd = dcast(FunctionDefn, fn); !fd) { error(fd, "invalid non-definition of a function with placeholder types"); } else { // ok, i guess. iceAssert(fd); iceAssert(fd->original); auto [ gmaps, err ] = resolver::misc::canonicalisePolyArguments(fs, fd->original, pams); if(err != nullptr) { fails[fn] = err; dist = -1; } else { // do an inference -- with the arguments that we have. auto [ res, soln ] = poly::attemptToInstantiatePolymorph(fs, fd->original, fn->id.name, gmaps, /* return_infer: */ return_infer, /* type_infer: */ nullptr, /* isFnCall: */ true, &replacementArgs, /* fillPlacholders: */ false, /* problem_infer: */ fn->type); if(!res.isDefn()) { fails[fn] = res.error(); dist = -1; } else { curcandidate = res.defn(); std::tie(dist, fails[fn]) = std::make_tuple(soln.distance, nullptr); } } } } else { // if it's not generic but you gave type args, you don't deserve to call it. //? we might change this if(!pams.empty()) { fails[fn] = complainAboutExtraneousPAMs("non-polymorphic function", fn, "called", /* printdef: */ true); } else { std::tie(dist, fails[fn]) = computeNamedOverloadDistance(fn->loc, fn->params, replacementArgs, fn->isVarArg, callLoc); } } //! SELF HANDLING (REMOVAL) (METHOD CALL) if(insertedSelf) replacementArgs.erase(replacementArgs.begin()); } else if(auto vr = dcast(VarDefn, curcandidate)) { iceAssert(vr->type->isFunctionType()); auto ft = vr->type->toFunctionType(); if(!pams.empty()) { fails[vr] = complainAboutExtraneousPAMs("variables", vr, "used", /* printdef: */ false); continue; } // check if have any names for(auto p : replacementArgs) { if(p.name != "") { return { TCResult(SimpleError::make(p.loc, "function values cannot be called with named arguments")->append( SimpleError::make(vr->loc, "'%s' was defined here:", vr->id.name)) ), { } }; } } auto prms = ft->getArgumentTypes(); std::tie(dist, fails[vr]) = computeOverloadDistance(curcandidate->loc, zfu::map(prms, [](fir::Type* t) -> fir::LocatedType { return fir::LocatedType(t, Location()); }), zfu::map(replacementArgs, [](const FnCallArgument& p) -> fir::LocatedType { return fir::LocatedType(p.value->type, Location()); }), /* isCVarArg: */ false, callLoc); } else if(auto td = dcast(TypeDefn, curcandidate)) { if(!pams.empty()) { if(!td->type->containsPlaceholders()) { fails[td] = complainAboutExtraneousPAMs("non-polymorphic type", td, "constructed", /* printdef: */ true); continue; } else if(auto uvd = dcast(UnionVariantDefn, curcandidate)) { // fails[td] = complainAboutExtraneousPAMs("non-polymorphic type", td, "constructed", /* printdef: */ true); fails[td] = SimpleError::make(fs->loc(), "type arguments should be specified on the union instead of the variant") ->append(ExampleMsg::make(strprintf("%s!<%s>::%s(...)", uvd->parentUnion->bareName, pams.print(), uvd->variantName)) ); continue; } } auto res = resolveConstructorCall(fs, callLoc, td, replacementArgs, pams); if(!res.isDefn()) { fails[td] = res.error(); dist = -1; } else { curcandidate = res.defn(); std::tie(dist, fails[td]) = std::make_tuple(0, nullptr); } } else { fails[curcandidate] = SimpleError::make(fs->loc(), "unsupported entity '%s'", curcandidate->getKind()); } if(dist == -1) continue; else if(dist < bestDist) finals.clear(), finals.push_back({ curcandidate, replacementArgs, dist }), bestDist = dist; else if(dist == bestDist) finals.push_back({ curcandidate, replacementArgs, dist }); } if(finals.empty()) { auto err = createErrorFromFailedCandidates(fs, callLoc, cands[0].first->id.name, cands[0].second, zfu::map(zfu::pairs(fails), [](auto p) -> std::pair { return std::make_pair(p.first, p.second); })); return { TCResult(err), { } }; } else if(finals.size() > 1) { // check if all of the targets we found are virtual, and that they belong to the same class. bool virt = true; fir::ClassType* self = 0; Defn* ret = std::get<0>(finals[0]); for(auto def : finals) { if(auto fd = dcast(sst::FunctionDefn, std::get<0>(def)); fd && fd->isVirtual) { iceAssert(fd->parentTypeForMethod); iceAssert(fd->parentTypeForMethod->isClassType()); if(!self) { self = fd->parentTypeForMethod->toClassType(); } else { // check if they're co/contra variant auto ty = fd->parentTypeForMethod->toClassType(); //* here we're just checking that 'ty' and 'self' are part of the same class hierarchy -- we don't really care about the method //* that we resolve being at the lowest or highest level of that hierarchy. if(!ty->hasParent(self) && !self->hasParent(ty)) { virt = false; break; } } } else { virt = false; break; } } if(virt) { return { TCResult(ret), std::get<1>(finals[0]) }; } else { auto err = SimpleError::make(callLoc, "ambiguous call to function '%s', have %d candidates:", cands[0].first->id.name, finals.size()); for(auto f : finals) { err->append(SimpleError::make(MsgType::Note, std::get<0>(f)->loc, "possible target (overload distance %d):", std::get<2>(f))); } return { TCResult(err), { } }; } } else { return { TCResult(std::get<0>(finals[0])), std::get<1>(finals[0]) }; } } } } } ================================================ FILE: source/typecheck/sizeof.cpp ================================================ // sizeof.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "pts.h" #include "errors.h" #include "ir/type.h" #include "typecheck.h" #include "memorypool.h" TCResult ast::SizeofOp::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); auto ret = util::pool(this->loc, fir::Type::getNativeWord()); if(dcast(ast::LitNumber, this->expr)) { error(this->expr, "literal numbers cannot be sized"); } this->expr->checkAsType = true; fir::Type* out = this->expr->typecheck(fs).expr()->type; iceAssert(out); ret->typeToSize = out; return TCResult(ret); } TCResult ast::TypeidOp::typecheck(sst::TypecheckState* fs, fir::Type* inferred) { fs->pushLoc(this); defer(fs->popLoc()); auto ret = util::pool(this->loc, fir::Type::getNativeUWord()); if(dcast(ast::LitNumber, this->expr)) { error(this->expr, "literal numbers cannot be typeid'd"); } this->expr->checkAsType = true; fir::Type* out = this->expr->typecheck(fs).expr()->type; iceAssert(out); ret->typeToId = out; return TCResult(ret); } ================================================ FILE: source/typecheck/slice.cpp ================================================ // slice.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "errors.h" #include "typecheck.h" #include "ir/type.h" #include "memorypool.h" bool sst::getMutabilityOfSliceOfType(fir::Type* ty) { if(ty->isStringType() || ty->isDynamicArrayType()) return true; else if(ty->isArrayType()) return false; else if(ty->isArraySliceType()) return ty->toArraySliceType()->isMutable(); else if(ty->isPointerType()) return ty->isMutablePointer(); else error("type '%s' does not have mutable variants", ty); } TCResult ast::SliceOp::typecheck(sst::TypecheckState* fs, fir::Type* inferred) { fs->pushLoc(this); defer(fs->popLoc()); fs->pushAnonymousTree(); defer(fs->popTree()); auto array = this->expr->typecheck(fs).expr(); auto ty = array->type; fs->enterSubscript(array); defer(fs->leaveSubscript()); fir::Type* elm = 0; if(ty->isDynamicArrayType() || ty->isArraySliceType() || ty->isArrayType()) elm = ty->getArrayElementType(); else if(ty->isStringType()) elm = fir::Type::getInt8(); else if(ty->isPointerType()) elm = ty->getPointerElementType(); else error(array, "invalid type '%s' for slice operation", ty); auto begin = this->start ? this->start->typecheck(fs, fir::Type::getNativeWord()).expr() : 0; auto end = this->end ? this->end->typecheck(fs, fir::Type::getNativeWord()).expr() : 0; if(begin && !begin->type->isIntegerType()) error(begin, "expected integer type for start index of slice; found '%s'", begin->type); if(end && !end->type->isIntegerType()) error(end, "expected integer type for end index of slice; found '%s'", end->type); //* how it goes: // 1. strings and dynamic arrays are always sliced mutably. // 2. slices of slices naturally inherit their mutability. // 3. arrays are sliced immutably. // 4. pointers inherit their mutability as well. bool ismut = sst::getMutabilityOfSliceOfType(ty); auto ret = util::pool(this->loc, fir::ArraySliceType::get(elm, ismut)); ret->expr = array; ret->begin = begin; ret->end = end; return TCResult(ret); } ================================================ FILE: source/typecheck/special.cpp ================================================ // misc.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "errors.h" #include "typecheck.h" #include "ir/type.h" #include "memorypool.h" TCResult ast::TypeExpr::typecheck(sst::TypecheckState* fs, fir::Type* infer) { auto ret = sst::TypeExpr::make(this->loc, fs->convertParserTypeToFIR(this->type)); return TCResult(ret); } TCResult ast::MutabilityTypeExpr::typecheck(sst::TypecheckState* fs, fir::Type* infer) { error(this, "unable to typecheck mutability cast, this shouldn't happen!"); } TCResult ast::ImportStmt::typecheck(sst::TypecheckState* fs, fir::Type* infer) { // nothing to check?? error(this->loc, "unexpected import statement"); } TCResult ast::SplatOp::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); auto inside = this->expr->typecheck(fs, infer).expr(); if(!inside->type->isArraySliceType() && !inside->type->isArrayType() && !inside->type->isDynamicArrayType() && !inside->type->isTupleType()) return TCResult(SimpleError::make(this->loc, "invalid use of splat operator on type '%s'", inside->type)); if(inside->type->isTupleType()) return TCResult(SimpleError::make(this->loc, "splat operator on tuple not allowed in this context")); auto ret = util::pool(this->loc, fir::ArraySliceType::getVariadic(inside->type->getArrayElementType())); ret->inside = inside; return TCResult(ret); } TCResult ast::Parameterisable::typecheck(sst::TypecheckState* fs, fir::Type* infer) { return this->typecheck(fs, infer, { }); } static util::hash_map cache; sst::TypeExpr* sst::TypeExpr::make(const Location& l, fir::Type* t) { if(auto it = cache.find(t); it != cache.end()) return it->second; return (cache[t] = util::pool(l, t)); } FnCallArgument FnCallArgument::make(const Location& l, const std::string& n, fir::Type* t, bool ignoreName) { auto te = sst::TypeExpr::make(l, t); auto ret = FnCallArgument(l, n, te, nullptr); ret.ignoreName = ignoreName; return ret; } ================================================ FILE: source/typecheck/structs.cpp ================================================ // structs.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "pts.h" #include "errors.h" #include "ir/type.h" #include "typecheck.h" #include #include "memorypool.h" static void _checkFieldRecursion(sst::TypecheckState* fs, fir::Type* strty, fir::Type* field, const Location& floc, std::set& seeing); static void _checkTransparentFieldRedefinition(sst::TypecheckState* fs, sst::TypeDefn* defn, const std::vector& fields, util::hash_map& seen); // used in typecheck/unions.cpp and typecheck/classes.cpp void checkFieldRecursion(sst::TypecheckState* fs, fir::Type* strty, fir::Type* field, const Location& floc) { std::set seeing; _checkFieldRecursion(fs, strty, field, floc, seeing); } void checkTransparentFieldRedefinition(sst::TypecheckState* fs, sst::TypeDefn* defn, const std::vector& fields) { util::hash_map seen; _checkTransparentFieldRedefinition(fs, defn, fields, seen); } // defined in typecheck/traits.cpp void checkTraitConformity(sst::TypecheckState* fs, sst::TypeDefn* defn); TCResult ast::StructDefn::generateDeclaration(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) { fs->pushLoc(this); defer(fs->popLoc()); auto [ success, ret ] = this->checkForExistingDeclaration(fs, gmaps); if(!success) return TCResult::getParametric(); else if(ret) return TCResult(ret); auto defnname = util::typeParamMapToString(this->name, gmaps); auto defn = util::pool(this->loc); defn->bareName = this->name; defn->attrs = this->attrs; defn->id = Identifier(defnname, IdKind::Type); defn->id.scope = this->enclosingScope; defn->visibility = this->visibility; defn->original = this; defn->enclosingScope = this->enclosingScope; defn->innerScope = this->enclosingScope.appending(defnname); // make all our methods be methods for(auto m : this->methods) { m->parentType = this; m->enclosingScope = defn->innerScope; } auto str = fir::StructType::createWithoutBody(defn->id.convertToName(), /* isPacked: */ this->attrs.has(attr::PACKED)); defn->type = str; if(auto err = fs->checkForShadowingOrConflictingDefinition(defn, [](auto, auto) -> bool { return true; })) return TCResult(err); // add it first so we can use it in the method bodies, // and make pointers to it { this->enclosingScope.stree->addDefinition(defnname, defn, gmaps); fs->typeDefnMap[str] = defn; } this->genericVersions.push_back({ defn, fs->getGenericContextStack() }); return TCResult(defn); } TCResult ast::StructDefn::typecheck(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) { fs->pushLoc(this); defer(fs->popLoc()); auto tcr = this->generateDeclaration(fs, infer, gmaps); if(tcr.isParametric()) return tcr; auto defn = dcast(sst::StructDefn, tcr.defn()); iceAssert(defn); if(this->finishedTypechecking.find(defn) != this->finishedTypechecking.end()) return TCResult(defn); auto str = defn->type->toStructType(); iceAssert(str); for(auto t : this->bases) { auto base = fs->convertParserTypeToFIR(t); if(!base->isTraitType()) error(this, "struct '%s' can only implement traits, which '%s' is not", this->name, base); auto tdef = dcast(sst::TraitDefn, fs->typeDefnMap[base]); iceAssert(tdef); defn->traits.push_back(tdef); str->addTraitImpl(tdef->type->toTraitType()); } fs->teleportInto(defn->innerScope); std::vector> tys; fs->pushSelfContext(str); { for(auto f : this->fields) { auto vdef = util::pool(std::get<1>(f)); vdef->immut = false; vdef->name = std::get<0>(f); vdef->initialiser = nullptr; vdef->type = std::get<2>(f); vdef->isField = true; auto v = dcast(sst::StructFieldDefn, vdef->typecheck(fs).defn()); iceAssert(v); if(v->id.name == "_") v->isTransparentField = true; defn->fields.push_back(v); tys.push_back({ v->id.name, v->type }); checkFieldRecursion(fs, str, v->type, v->loc); } //* generate all the decls first so we can call methods out of order. for(auto m : this->methods) { auto res = m->generateDeclaration(fs, str, { }); if(res.isParametric()) continue; auto decl = dcast(sst::FunctionDefn, res.defn()); iceAssert(decl); defn->methods.push_back(decl); } for(auto m : this->methods) m->typecheck(fs, str, { }); } checkTransparentFieldRedefinition(fs, defn, defn->fields); fs->popSelfContext(); str->setBody(tys); fs->teleportOut(); checkTraitConformity(fs, defn); this->finishedTypechecking.insert(defn); return TCResult(defn); } static void _checkFieldRecursion(sst::TypecheckState* fs, fir::Type* strty, fir::Type* field, const Location& floc, std::set& seeing) { seeing.insert(strty); if(field == strty) { SimpleError::make(floc, "composite type '%s' cannot contain a field of its own type; use a pointer.", strty) ->append(SimpleError::make(MsgType::Note, fs->typeDefnMap[strty]->loc, "type '%s' was defined here:", strty)) ->postAndQuit(); } else if(seeing.find(field) != seeing.end()) { SimpleError::make(floc, "recursive definition of field with a non-pointer type; mutual recursion between types '%s' and '%s'", field, strty) ->append(SimpleError::make(MsgType::Note, fs->typeDefnMap[strty]->loc, "type '%s' was defined here:", strty)) ->postAndQuit(); } else if(field->isClassType()) { for(auto f : field->toClassType()->getElements()) _checkFieldRecursion(fs, field, f, floc, seeing); } else if(field->isStructType()) { for(auto f : field->toStructType()->getElements()) _checkFieldRecursion(fs, field, f, floc, seeing); } else if(field->isRawUnionType()) { for(auto f : field->toRawUnionType()->getVariants()) _checkFieldRecursion(fs, field, f.second, floc, seeing); } // ok, we should be fine...? } static void _checkTransparentFieldRedefinition(sst::TypecheckState* fs, sst::TypeDefn* defn, const std::vector& fields, util::hash_map& seen) { for(auto fld : fields) { if(fld->isTransparentField) { auto ty = fld->type; if(!ty->isRawUnionType() && !ty->isStructType()) { // you can't have a transparentl field if it's not an aggregate type, lmao error(fld, "transparent fields must have either a struct or raw-union type."); } auto innerdef = fs->typeDefnMap[ty]; iceAssert(innerdef); std::vector flds; if(auto str = dcast(sst::StructDefn, innerdef); str) flds = str->fields; else if(auto unn = dcast(sst::RawUnionDefn, innerdef); unn) flds = zfu::map(unn->fields, zfu::pair_second()) + unn->transparentFields; else error(fs->loc(), "what kind of type is this? '%s'", ty); _checkTransparentFieldRedefinition(fs, innerdef, flds, seen); } else { if(auto it = seen.find(fld->id.name); it != seen.end()) { SimpleError::make(fld->loc, "redefinition of transparently accessible field '%s'", fld->id.name) ->append(SimpleError::make(MsgType::Note, it->second, "previous definition was here:")) ->postAndQuit(); } else { seen[fld->id.name] = fld->loc; } } } } ================================================ FILE: source/typecheck/subscript.cpp ================================================ // subscript.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "errors.h" #include "typecheck.h" #include "ir/type.h" #include "memorypool.h" TCResult ast::SubscriptOp::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); fs->pushAnonymousTree(); defer(fs->popTree()); auto ls = this->expr->typecheck(fs).expr(); fs->enterSubscript(ls); defer(fs->leaveSubscript()); auto rs = this->inside->typecheck(fs).expr(); // check what's the type auto lt = ls->type; auto rt = rs->type; if((rt->isConstantNumberType() && rt->toConstantNumberType()->isFloating()) && !rt->isIntegerType()) error(this->inside, "subscript index must be an integer type, found '%s'", rt); fir::Type* res = 0; // check what it is, then if(lt->isDynamicArrayType()) res = lt->toDynamicArrayType()->getElementType(); else if(lt->isArraySliceType()) res = lt->toArraySliceType()->getElementType(); else if(lt->isPointerType()) res = lt->getPointerElementType(); else if(lt->isArrayType()) res = lt->toArrayType()->getElementType(); else if(lt->isStringType()) res = fir::Type::getInt8(); else error(this->expr, "cannot subscript type '%s'", lt); iceAssert(res); auto ret = util::pool(this->loc, res); ret->expr = ls; ret->inside = rs; return TCResult(ret); } TCResult ast::SubscriptDollarOp::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); if(!fs->isInSubscript()) error(this, "invalid use of '$' in non-subscript context"); else if(auto arr = fs->getCurrentSubscriptArray(); arr->type->isPointerType() || !(arr->type->isArraySliceType() || arr->type->isArrayType() || arr->type->isStringType() || arr->type->isDynamicArrayType())) { SpanError::make(SimpleError::make(this->loc, "invalid use of '$' on subscriptee with %stype '%s'", arr->type->isPointerType() ? "pointer " : "", arr->type)) ->add(util::ESpan(arr->loc, "here"))->postAndQuit(); } return TCResult(util::pool(this->loc, fir::Type::getNativeWord())); } ================================================ FILE: source/typecheck/toplevel.cpp ================================================ // toplevel.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include #include "defs.h" #include "sst.h" #include "ast.h" #include "pts.h" #include "errors.h" #include "parser.h" #include "frontend.h" #include "typecheck.h" #include "string_consts.h" #include "ir/type.h" #include "memorypool.h" using namespace ast; namespace sst { struct OsStrings { std::string name; std::string vendor; }; static OsStrings getOsStrings(); static void generatePreludeDefinitions(TypecheckState* fs, const std::string& filename); static bool definitionsConflict(const sst::Defn* a, const sst::Defn* b) { auto fda = dcast(const sst::FunctionDecl, a); auto fdb = dcast(const sst::FunctionDecl, b); auto uva = dcast(const sst::UnionVariantDefn, a); auto uvb = dcast(const sst::UnionVariantDefn, b); if(fda && fdb) { return sst::isDuplicateOverload(fda->params, fdb->params); } else if(uva && uvb) { return uva->parentUnion == uvb->parentUnion; } else { return true; } } struct ExportMetadata { Location loc; std::string module; std::string imported; }; static void checkConflictingDefinitions(Location loc, const char* kind, const sst::StateTree* base, const sst::StateTree* branch, std::optional importer = { }, std::optional exporter = { }) { for(const auto& [ name, defns ] : base->definitions) { if(auto it = branch->definitions.find(name); it != branch->definitions.end()) { for(auto d1 : defns) { for(auto d2 : it->second) { if(!definitionsConflict(d1, d2)) continue; auto error = SimpleError::make(MsgType::Error, loc, "'%s' here introduces duplicate definitions:", kind); if(d1 == d2) { if(importer && exporter) { error->append(SimpleError::make(MsgType::Note, exporter->loc, "this public import (from the imported module '%s') brings '%s' into scope ...", exporter->module, exporter->imported)); error->append(SimpleError::make(MsgType::Note, *importer, "... which conflicts with this using/import statement here:")); } else if(importer) { error->append(SimpleError::make(MsgType::Note, *importer, "most likely caused by this import here:")); } else if(exporter) { error->append(SimpleError::make(MsgType::Note, exporter->loc, "most likely caused by this public import here, in module '%s':", exporter->module)); } error->append(SimpleError::make(MsgType::Note, d1->loc, "for reference, here is the (first) " "conflicting definition:")); } else { error->append(SimpleError::make(MsgType::Note, d1->loc, "first definition here:")) ->append(SimpleError::make(MsgType::Note, d2->loc, "second definition here:")); } error->postAndQuit(); } } } } } static std::optional getExportInfo(const sst::StateTree* base, const sst::StateTree* branch) { if(auto it = base->reexportMetadata.find(branch); it != base->reexportMetadata.end()) { return ExportMetadata { .loc = it->second, .module = base->moduleName, .imported = branch->name }; } return { }; } static void checkExportsRecursively(const Location& loc, const char* kind, sst::StateTree* base, sst::StateTree* branch, std::optional importer = { }, std::optional exporter = { }) { if(branch->isAnonymous || branch->isCompilerGenerated) return; checkConflictingDefinitions(loc, kind, base, branch, importer, exporter); for(auto exp : base->reexports) checkExportsRecursively(loc, kind, exp, branch, importer, getExportInfo(base, exp)); } void mergeExternalTree(const Location& loc, const char* kind, sst::StateTree* base, sst::StateTree* branch) { if(branch->isAnonymous || branch->isCompilerGenerated) return; // first check conflicts for this level: checkConflictingDefinitions(loc, kind, base, branch); // then, for every one of *our* imports: for(auto import : base->imports) { std::optional importer; if(auto it = base->importMetadata.find(import); it != base->importMetadata.end()) importer = it->second; // check that the new tree doesn't trample over it. checkConflictingDefinitions(loc, kind, import, branch, importer); // then, recursively check every single re-export on *our* side for conflicts: for(auto rexp : import->reexports) checkExportsRecursively(loc, kind, rexp, branch, importer, getExportInfo(import, rexp)); // then, also check that, for every one of *their* public imports: for(auto rexp : branch->reexports) { auto exportInfo = getExportInfo(import, rexp); // it doesn't trample with anything in our tree, checkConflictingDefinitions(loc, kind, base, rexp, importer, exportInfo); // and it doesn't conflict with anything in our imports. checkConflictingDefinitions(loc, kind, import, rexp, importer, exportInfo); // finally, also check that, for every one of *our* imports' re-exports, for(auto rexp2 : import->reexports) { auto exportInfo = getExportInfo(import, rexp2); // check that *they* don't trample anything: checkConflictingDefinitions(loc, kind, rexp2, branch, importer, exportInfo); // and neither does their reexport: checkConflictingDefinitions(loc, kind, rexp2, rexp, importer, exportInfo); } } } // no problem -- attach the trees base->imports.push_back(branch); base->importMetadata[branch] = loc; // merge the subtrees as well. for(const auto& [ name, tr ] : branch->subtrees) { if(tr->isCompilerGenerated || tr->isAnonymous) continue; mergeExternalTree(loc, kind, base->findOrCreateSubtree(name), tr); } } DefinitionTree* typecheck(frontend::CollectorState* cs, const parser::ParsedFile& file, const std::vector>& imports, bool addPreludeDefinitions) { auto tree = new StateTree(file.moduleName, nullptr); tree->moduleName = file.moduleName; auto fs = new TypecheckState(tree); for(auto [ ithing, import ] : imports) { auto ias = ithing.importAs; if(ias.empty()) ias = cs->parsed[ithing.name].modulePath + cs->parsed[ithing.name].moduleName; StateTree* insertPoint = tree; if(ias.size() == 1 && ias[0] == "_") { // do nothing. // insertPoint = tree; } else { StateTree* curinspt = insertPoint; // iterate through the import-as list, which is a list of nested scopes to import into // eg we can `import foo as some::nested::namespace`, which means we need to create // the intermediate trees. for(const auto& impas : ias) { if(impas == curinspt->name) { // skip it. } else if(auto it = curinspt->subtrees.find(impas); it != curinspt->subtrees.end()) { curinspt = it->second; } else { auto newinspt = curinspt->findOrCreateSubtree(impas); curinspt->subtrees[impas] = newinspt; curinspt = newinspt; } } insertPoint = curinspt; insertPoint->proxyOf = import->base; } iceAssert(insertPoint); mergeExternalTree(ithing.loc, "import", insertPoint, import->base); if(ithing.pubImport) { insertPoint->reexports.push_back(import->base); insertPoint->reexportMetadata[import->base] = ithing.loc; } fs->dtree->thingsImported.insert(ithing.name); fs->dtree->typeDefnMap.insert(import->typeDefnMap.begin(), import->typeDefnMap.end()); // merge the things. hopefully there are no conflicts???? // TODO: check for conflicts! fs->dtree->compilerSupportDefinitions.insert(import->compilerSupportDefinitions.begin(), import->compilerSupportDefinitions.end()); } if(addPreludeDefinitions) generatePreludeDefinitions(fs, file.name); // handle exception here: try { auto tns = dcast(NamespaceDefn, file.root->typecheck(fs).stmt()); iceAssert(tns); tns->name = file.moduleName; fs->dtree->topLevel = tns; } catch(ErrorException& ee) { ee.err->postAndQuit(); } return fs->dtree; } static OsStrings getOsStrings() { // TODO: handle cygwin/msys/mingw??? // like how do we want to expose these? at the end of the day the os is still windows... // TODO: this should be set for the target we are compiling FOR, so it definitely // cannot be done using ifdefs!!!!!!!!!! OsStrings ret; #if defined(_WIN32) ret.name = "windows"; ret.vendor = "microsoft"; #elif __MINGW__ ret.name = "mingw"; #elif __CYGWIN__ ret.name = "cygwin"; #elif __APPLE__ ret.vendor = "apple"; #include "TargetConditionals.h" #if TARGET_IPHONE_SIMULATOR ret.name = "iossimulator"; #elif TARGET_OS_IOS ret.name = "ios"; #elif TARGET_OS_WATCH ret.name = "watchos"; #elif TARGET_OS_TV ret.name = "tvos"; #elif TARGET_OS_OSX ret.name = "macos"; #else #error "unknown apple operating system" #endif #elif __ANDROID__ ret.vendor = "google"; ret.name = "android"; #elif __linux__ || __linux || linux ret.name = "linux"; #elif __FreeBSD__ ret.name = "freebsd"; #elif __OpenBSD__ ret.name = "openbsd"; #elif __NetBSD__ ret.name = "netbsd"; #elif __DragonFly__ ret.name = "dragonflybsd"; #elif __unix__ ret.name = "unix"; #elif defined(_POSIX_VERSION) ret.name = "posix"; #endif return ret; } static void generatePreludeDefinitions(TypecheckState* fs, const std::string& filename) { auto loc = Location(); loc.fileID = frontend::getFileIDFromFilename(filename); auto strings = getOsStrings(); fs->pushTree("os"); fs->stree->isCompilerGenerated = true; defer(fs->popTree()); auto strty = fir::Type::getCharSlice(false); { // add the name auto name_def = util::pool(loc); name_def->id = Identifier("name", IdKind::Name); name_def->type = strty; name_def->global = true; name_def->immutable = true; name_def->visibility = VisibilityLevel::Private; auto s = util::pool(loc, strty); s->str = strings.name; name_def->init = s; fs->stree->addDefinition("name", name_def); } { // add the name auto vendor_def = util::pool(loc); vendor_def->id = Identifier("vendor", IdKind::Name); vendor_def->type = strty; vendor_def->global = true; vendor_def->immutable = true; vendor_def->visibility = VisibilityLevel::Private; auto s = util::pool(loc, strty); s->str = strings.vendor; vendor_def->init = s; fs->stree->addDefinition("vendor", vendor_def); } } } static void visitDeclarables(sst::TypecheckState* fs, ast::TopLevelBlock* top) { for(auto stmt : top->statements) { if(auto decl = dcast(ast::Parameterisable, stmt)) { decl->enclosingScope = fs->scope(); decl->generateDeclaration(fs, 0, { }); } else if(auto ffd = dcast(ast::ForeignFuncDefn, stmt)) ffd->typecheck(fs); else if(auto ns = dcast(ast::TopLevelBlock, stmt)) { fs->pushTree(ns->name); visitDeclarables(fs, ns); fs->popTree(); } } } TCResult ast::TopLevelBlock::typecheck(sst::TypecheckState* fs, fir::Type* inferred) { auto ret = util::pool(this->loc); if(this->name != "") fs->pushTree(this->name); sst::StateTree* tree = fs->stree; if(!fs->isInFunctionBody()) { // visit all functions first, to get out-of-order calling -- but only at the namespace level, not inside functions. // once we're in function-body-land, everything should be imperative-driven, and you shouldn't // be able to see something before it is defined/declared visitDeclarables(fs, this); } for(auto stmt : this->statements) { if(dcast(ast::ImportStmt, stmt)) continue; auto tcr = stmt->typecheck(fs); if(tcr.isError()) return TCResult(tcr.error()); else if(!tcr.isParametric() && !tcr.isDummy()) ret->statements.push_back(tcr.stmt()); if(tcr.isDefn() && tcr.defn()->visibility == VisibilityLevel::Public) tree->exports.push_back(tcr.defn()); // check for compiler support so we can add it to the big list of things. if((tcr.isStmt() || tcr.isDefn()) && tcr.stmt()->attrs.has(strs::attrs::COMPILER_SUPPORT)) { if(!tcr.isDefn()) error(tcr.stmt(), "@compiler_support can only be applied to definitions"); auto ua = tcr.stmt()->attrs.get(strs::attrs::COMPILER_SUPPORT); iceAssert(!ua.name.empty() && ua.args.size() == 1); fs->dtree->compilerSupportDefinitions[ua.args[0]] = tcr.defn(); } } if(this->name != "") fs->popTree(); ret->name = this->name; return TCResult(ret); } ================================================ FILE: source/typecheck/traits.cpp ================================================ // traits.cpp // Copyright (c) 2019, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "errors.h" #include "typecheck.h" #include "polymorph.h" #include "memorypool.h" #include "ir/type.h" TCResult ast::TraitDefn::generateDeclaration(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) { fs->pushLoc(this); defer(fs->popLoc()); auto [ success, ret ] = this->checkForExistingDeclaration(fs, gmaps); if(!success) return TCResult::getParametric(); else if(ret) return TCResult(ret); auto defnname = util::typeParamMapToString(this->name, gmaps); auto defn = util::pool(this->loc); defn->bareName = this->name; defn->attrs = this->attrs; defn->id = Identifier(defnname, IdKind::Type); defn->id.scope = this->enclosingScope; defn->visibility = this->visibility; defn->original = this; defn->enclosingScope = this->enclosingScope; defn->innerScope = this->enclosingScope.appending(defnname); // make all our methods be methods for(auto m : this->methods) { m->parentType = this; m->enclosingScope = defn->innerScope; } auto str = fir::TraitType::create(defn->id.convertToName()); defn->type = str; if(auto err = fs->checkForShadowingOrConflictingDefinition(defn, [](auto, auto) -> bool { return true; })) return TCResult(err); // add it first so we can use it in the method bodies, // and make pointers to it { defn->enclosingScope.stree->addDefinition(defnname, defn, gmaps); fs->typeDefnMap[str] = defn; } this->genericVersions.push_back({ defn, fs->getGenericContextStack() }); return TCResult(defn); } TCResult ast::TraitDefn::typecheck(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) { fs->pushLoc(this); defer(fs->popLoc()); auto tcr = this->generateDeclaration(fs, infer, gmaps); if(tcr.isParametric()) return tcr; auto defn = dcast(sst::TraitDefn, tcr.defn()); iceAssert(defn); if(this->finishedTypechecking.find(defn) != this->finishedTypechecking.end()) return TCResult(defn); auto trt = defn->type->toTraitType(); iceAssert(trt); fs->teleportInto(defn->innerScope); fs->pushSelfContext(trt); std::vector> meths; for(auto m : this->methods) { // make sure we don't have bodies -- for now! iceAssert(m->body == 0); auto res = m->generateDeclaration(fs, 0, { }); if(res.isParametric()) continue; auto decl = dcast(sst::FunctionDecl, res.defn()); iceAssert(decl); defn->methods.push_back(decl); meths.push_back({ m->name, decl->type->toFunctionType() }); } trt->setMethods(meths); fs->popSelfContext(); fs->teleportOut(); this->finishedTypechecking.insert(defn); return TCResult(defn); } // used by typecheck/structs.cpp and typecheck/classes.cpp static bool _checkFunctionTypesMatch(fir::Type* trait, fir::Type* type, fir::FunctionType* required, fir::FunctionType* candidate) { auto as = required->getArgumentTypes() + required->getReturnType(); auto bs = candidate->getArgumentTypes() + candidate->getReturnType(); // all candidates must have a self!! iceAssert(as.size() > 0 && bs.size() > 0); if(as.size() != bs.size()) return false; for(size_t i = 0; i < as.size(); i++) { auto ax = as[i]; auto bx = bs[i]; // TODO: wtf is this doing?! if(ax != bx) { auto [ abase, atrfs ] = sst::poly::internal::decomposeIntoTransforms(ax, SIZE_MAX); auto [ bbase, btrfs ] = sst::poly::internal::decomposeIntoTransforms(bx, SIZE_MAX); if(atrfs != btrfs) return false; if(abase != trait || bbase != type) return false; } } return true; } // TODO: needs to handle extensions!!! void checkTraitConformity(sst::TypecheckState* fs, sst::TypeDefn* defn) { std::vector traits; util::hash_map> methods; if(auto cls = dcast(sst::ClassDefn, defn)) { for(auto m : cls->methods) methods[m->id.name].push_back(m); error("wait a bit"); } else if(auto str = dcast(sst::StructDefn, defn)) { for(auto m : str->methods) methods[m->id.name].push_back(m); traits = str->traits; } else { return; } // make this a little less annoying: report errors by trait, so all the missing methods for a trait are given at once for(auto trait : traits) { std::vector> missings; for(auto meth : trait->methods) { auto cands = methods[meth->id.name]; bool found = false; for(auto cand : cands) { // c++ really fucking needs named arguments!! if(_checkFunctionTypesMatch(trait->type, defn->type, /* required: */ meth->type->toFunctionType(), /* candidate: */ cand->type->toFunctionType() )) { found = true; break; } } if(!found) missings.push_back({ meth->loc, meth->id.name, meth->type->toFunctionType() }); } if(missings.size() > 0) { auto err = SimpleError::make(defn->loc, "type '%s' does not conform to trait '%s'", defn->id.name, trait->id.name); for(const auto& m : missings) { err->append(SimpleError::make(MsgType::Note, std::get<0>(m), "missing implementation for method '%s': %s:", std::get<1>(m), std::get<2>(m))); } err->append( SimpleError::make(MsgType::Note, trait->loc, "trait '%s' was defined here:", trait->id.name) )->postAndQuit(); } } } ================================================ FILE: source/typecheck/type.cpp ================================================ // type.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "pts.h" #include "errors.h" #include "ir/type.h" #include "typecheck.h" #include "resolver.h" #include "polymorph.h" #include namespace sst { fir::Type* inferCorrectTypeForLiteral(fir::ConstantNumberType* type) { auto ty = type->toConstantNumberType(); { if(ty->isFloating()) { if(ty->getMinBits() <= fir::Type::getFloat64()->getBitWidth()) return fir::Type::getFloat64(); else if(ty->getMinBits() <= fir::Type::getFloat128()->getBitWidth()) return fir::Type::getFloat128(); else error("float overflow"); } else { if(ty->getMinBits() <= fir::Type::getNativeWord()->getBitWidth() - 1) return fir::Type::getNativeWord(); else if(!ty->isSigned() && ty->getMinBits() <= fir::Type::getNativeUWord()->getBitWidth()) return fir::Type::getNativeUWord(); else error("int overflow"); } } } static ErrorMsg* _complainNoParentScope(TypecheckState* fs, const std::string& top) { return SimpleError::make(fs->loc(), "invalid use of '^' at the topmost scope '%s'", top); } static StateTree* recursivelyFindTreeUpwards(TypecheckState* fs, const std::string& name) { auto from = fs->stree; if(name == "^") { if(!from->parent) _complainNoParentScope(fs, from->name)->postAndQuit(); // move to our parent scope. while(from->parent && from->isAnonymous) from = from->parent; return from; } while(from) { if(from->name == name) return from; else if(auto it = from->subtrees.find(name); it != from->subtrees.end()) return it->second; from = from->parent; } return 0; } fir::Type* TypecheckState::convertParserTypeToFIR(pts::Type* pt, bool allowFail) { //* note: 'allowFail' allows failure when we *don't find anything* //* but if we find something _wrong_, then we will always fail. iceAssert(pt); this->pushLoc(pt->loc); defer(this->popLoc()); if(pt->isNamedType()) { auto builtin = fir::Type::fromBuiltin(pt->toNamedType()->str()); if(builtin) { return builtin; } else { auto name = pt->toNamedType()->name; if(name == "self") { if(!this->hasSelfContext()) error(this->loc(), "invalid use of 'self' type while not in method body"); else return this->getCurrentSelfContext(); } auto returnTheThing = [this, pt](StateTree* tree, const std::string& name, bool scoped, bool allowFail) -> fir::Type* { if(auto gmt = this->findGenericMapping(name, true)) return gmt; std::vector defs; if(scoped) defs = tree->getDefinitionsWithName(name); else defs = this->getDefinitionsWithName(name); if(defs.empty()) { // try generic defs. StateTree* str = (scoped ? tree : this->stree); std::vector gdefs; while(str && (gdefs = str->getUnresolvedGenericDefnsWithName(name)).size() == 0) str = (scoped ? 0 : str->parent); // if we're scoped, we can't go upwards. if(gdefs.empty()) { if(allowFail) return 0; else error(this->loc(), "no type named '%s' in scope '%s'", name, tree->name); } else if(gdefs.size() > 1) { auto err = SimpleError::make(this->loc(), "ambiguous reference to entity '%s' in scope", name); for(auto d : gdefs) err->append(SimpleError::make(MsgType::Note, d->loc, "possible reference:")); err->postAndQuit(); } // TODO: not re-entrant either. auto restore = this->stree; this->stree = (scoped ? tree : str); iceAssert(this->stree); { auto gdef = gdefs[0]; iceAssert(gdef); auto atd = dcast(ast::TypeDefn, gdef); if(!atd) error(this->loc(), "entity '%s' is not a type", name); if(pt->toNamedType()->genericMapping.empty()) error(this->loc(), "parametric type '%s' cannot be referenced without type arguments", pt->toNamedType()->name); // right, now we instantiate it. auto [ mapping, err ] = sst::resolver::misc::canonicalisePolyArguments(this, gdef, pt->toNamedType()->genericMapping); if(err != nullptr) { err->prepend(BareError::make("mismatched type arguments to instantiation of polymorphic type '%s':", gdef->name) )->postAndQuit(); } // types generally cannot be overloaded, so it doesn't make sense for it to be SFINAE-ed. // unwrapping it will post the error if any. auto td = poly::fullyInstantiatePolymorph(this, atd, mapping).defn(); this->stree = restore; return td->type; } } else if(defs.size() > 1) { auto err = SimpleError::make(this->loc(), "ambiguous reference to entity '%s' in scope '%s'", name, tree->name); for(auto d : defs) err->append(SimpleError::make(MsgType::Note, d->loc, "possible reference:")); err->postAndQuit(); } auto d = defs[0]; auto tyd = dcast(TypeDefn, d); if(!tyd) { // helpful error message: see if there's a actually a type further up! ErrorMsg* extraHelp = 0; { auto t = tree->parent; while(!extraHelp && t) { if(auto ds = t->getDefinitionsWithName(name); ds.size() > 0) { for(const auto& d : ds) { if(dcast(sst::TypeDefn, d)) { std::vector ss; auto t1 = tree; while(t1 != t) { t1 = t1->parent; if(!t1->isAnonymous) ss.push_back("^"); } ss.push_back(name); extraHelp = SimpleError::make(MsgType::Note, d->loc, "'%s' was defined as a type in the parent scope, here:", name) ->append(BareError::make(MsgType::Note, "to refer to it, use '%s'", zfu::join(ss, "::"))); } } } t = t->parent; } } //* example of something 'wrong' auto err = SimpleError::make(this->loc(), "definition of '%s' cannot be used as a type", d->id.name) ->append(SimpleError::make(MsgType::Note, d->loc, "'%s' was defined here:", d->id.name)); if(extraHelp) err->append(extraHelp); err->postAndQuit(); } return tyd->type; }; if(name.find("::") == std::string::npos) { return returnTheThing(this->stree, name, false, allowFail); } else { // fuck me std::string actual; bool skip_to_root = false; std::deque scopes; { std::string tmp; for(size_t i = 0; i < name.size(); i++) { if(name[i] == ':' && (i + 1 < name.size()) && name[i+1] == ':') { if(tmp.empty()) { if(i == 0) { i++; skip_to_root = true; continue; } else { error(this->loc(), "expected identifier between consecutive scopes ('::') in nested type specifier"); } } scopes.push_back(tmp); tmp.clear(); i++; } else if(name[i] == '^') { if(!tmp.empty()) error(this->loc(), "parent-scope-specifier '^' must appear in its own path segment ('%s' is invalid)", tmp + name[i]); else tmp = "^"; } else { tmp += name[i]; } } if(tmp.empty()) error(this->loc(), "expected identifier after final '::' in nested type specifier"); // don't push back. actual = tmp; } StateTree* begin = 0; if(skip_to_root) { begin = this->stree; while(begin->parent) begin = begin->parent; } else { iceAssert(scopes.size() > 0); begin = recursivelyFindTreeUpwards(this, scopes.front()); } if(!begin) { if(allowFail) return 0; else error(this->loc(), "nonexistent scope '%s'", scopes.front()); } if(scopes.size() > 0) { std::string prev = scopes.front(); if(!skip_to_root) scopes.pop_front(); while(scopes.size() > 0) { if(scopes.front() == "^") { if(!begin->parent) _complainNoParentScope(this, begin->name)->postAndQuit(); while(begin->parent && begin->isAnonymous) begin = begin->parent; } else { auto it = begin->subtrees.find(scopes.front()); if(it == begin->subtrees.end()) { if(allowFail) return 0; else error(this->loc(), "no entity '%s' in scope '%s'", scopes.front(), prev); } begin = it->second; } prev = scopes.front(); scopes.pop_front(); } } return returnTheThing(begin, actual, true, allowFail); } } } else if(pt->isPointerType()) { if(pt->toPointerType()->isMutable) return this->convertParserTypeToFIR(pt->toPointerType()->base)->getMutablePointerTo(); else return this->convertParserTypeToFIR(pt->toPointerType()->base)->getPointerTo(); } else if(pt->isTupleType()) { std::vector ts; for(auto t : pt->toTupleType()->types) ts.push_back(this->convertParserTypeToFIR(t)); return fir::TupleType::get(ts); } else if(pt->isArraySliceType()) { return fir::ArraySliceType::get(this->convertParserTypeToFIR(pt->toArraySliceType()->base), pt->toArraySliceType()->mut); } else if(pt->isDynamicArrayType()) { return fir::DynamicArrayType::get(this->convertParserTypeToFIR(pt->toDynamicArrayType()->base)); } else if(pt->isVariadicArrayType()) { return fir::ArraySliceType::getVariadic(this->convertParserTypeToFIR(pt->toVariadicArrayType()->base)); } else if(pt->isFixedArrayType()) { return fir::ArrayType::get(this->convertParserTypeToFIR(pt->toFixedArrayType()->base), pt->toFixedArrayType()->size); } else if(pt->isFunctionType()) { std::vector ps; for(auto p : pt->toFunctionType()->argTypes) ps.push_back(this->convertParserTypeToFIR(p)); auto ret = this->convertParserTypeToFIR(pt->toFunctionType()->returnType); return fir::FunctionType::get(ps, ret); } else { error(this->loc(), "invalid pts::Type found"); } } } ================================================ FILE: source/typecheck/typecheckstate.cpp ================================================ // typecheckstate.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "defs.h" #include "errors.h" #include "typecheck.h" #include "ir/type.h" #include "memorypool.h" #include "zfu.h" #include #include #include namespace sst { void TypecheckState::pushLoc(ast::Stmt* stmt) { this->locationStack.push_back(stmt->loc); } void TypecheckState::pushLoc(const Location& l) { this->locationStack.push_back(l); } Location TypecheckState::popLoc() { iceAssert(this->locationStack.size() > 0); auto last = this->locationStack.back(); this->locationStack.pop_back(); return last; } Location TypecheckState::loc() { iceAssert(this->locationStack.size() > 0); return this->locationStack.back(); } #define BODY_FUNC 1 #define BODY_STRUCT 2 void TypecheckState::enterFunctionBody(FunctionDefn* fn) { this->currentFunctionStack.push_back(fn); this->bodyStack.push_back(BODY_FUNC); } void TypecheckState::leaveFunctionBody() { if(this->currentFunctionStack.empty()) error(this->loc(), "not inside function"); this->currentFunctionStack.pop_back(); iceAssert(this->bodyStack.back() == BODY_FUNC); this->bodyStack.pop_back(); } FunctionDefn* TypecheckState::getCurrentFunction() { if(this->currentFunctionStack.empty()) error(this->loc(), "not inside function"); return this->currentFunctionStack.back(); } bool TypecheckState::isInFunctionBody() { return this->currentFunctionStack.size() > 0 && this->bodyStack.back() == BODY_FUNC; } fir::Type* TypecheckState::getCurrentSelfContext() { if(this->selfContextStack.empty()) error(this->loc(), "not inside struct body"); return this->selfContextStack.back(); } bool TypecheckState::hasSelfContext() { return this->selfContextStack.size() > 0; } void TypecheckState::pushSelfContext(fir::Type* str) { this->selfContextStack.push_back(str); this->bodyStack.push_back(BODY_STRUCT); } void TypecheckState::popSelfContext() { if(this->selfContextStack.empty()) error(this->loc(), "not inside struct body"); this->selfContextStack.pop_back(); iceAssert(this->bodyStack.back() == BODY_STRUCT); this->bodyStack.pop_back(); } void TypecheckState::enterSubscript(Expr* arr) { this->subscriptArrayStack.push_back(arr); } Expr* TypecheckState::getCurrentSubscriptArray() { iceAssert(this->subscriptArrayStack.size() > 0); return this->subscriptArrayStack.back(); } void TypecheckState::leaveSubscript() { iceAssert(this->subscriptArrayStack.size() > 0); this->subscriptArrayStack.pop_back(); } bool TypecheckState::isInSubscript() { return this->subscriptArrayStack.size() > 0; } void TypecheckState::pushTree(const std::string& name, bool createAnonymously) { iceAssert(this->stree); this->stree = this->stree->findOrCreateSubtree(name, createAnonymously); } StateTree* TypecheckState::popTree() { iceAssert(this->stree); auto ret = this->stree; this->stree = this->stree->parent; return ret; } void TypecheckState::enterBreakableBody() { this->breakableBodyNest++; } void TypecheckState::leaveBreakableBody() { iceAssert(this->breakableBodyNest > 0); this->breakableBodyNest--; } bool TypecheckState::isInBreakableBody() { return this->breakableBodyNest > 0; } void TypecheckState::enterDeferBlock() { this->deferBlockNest++; } void TypecheckState::leaveDeferBlock() { iceAssert(this->deferBlockNest > 0); this->deferBlockNest--; } bool TypecheckState::isInDeferBlock() { return this->deferBlockNest > 0; } Scope TypecheckState::scope() { return this->stree->getScope(); } std::vector StateTree::getAllDefinitions() { std::vector ret; for(const auto& [ n, ds ] : this->definitions) for(auto d : ds) ret.push_back(d); return ret; } static void fetchDefinitionsFrom(const std::string& name, StateTree* tree, bool recursively, bool includePrivate, std::vector& out) { if(auto it = tree->definitions.find(name); it != tree->definitions.end()) { std::copy_if(it->second.begin(), it->second.end(), std::back_inserter(out), [includePrivate](Defn* defn) -> bool { return (includePrivate ? true : defn->visibility == VisibilityLevel::Public); }); } auto sameOrigin = [](const StateTree* a, const StateTree* b) -> bool { auto p1 = a; while(p1->parent) p1 = p1->parent; auto p2 = b; while(p2->parent) p2 = p2->parent; return p1 == p2; }; for(auto import : tree->imports) { if(recursively) { // only include private things if we're in the same file. bool priv = sameOrigin(tree, import); fetchDefinitionsFrom(name, import, /* recursively: */ false, /* includePrivate: */ priv, out); } // in theory we should never include the private definitions from re-exports for(auto reexp : import->reexports) fetchDefinitionsFrom(name, reexp, /* recursively: */ false, /* includePrivate: */ false, out); } } std::vector StateTree::getDefinitionsWithName(const std::string& name) { std::vector ret; fetchDefinitionsFrom(name, this, /* recursively: */ true, /* includePrivate: */ true, ret); return ret; } std::vector StateTree::getUnresolvedGenericDefnsWithName(const std::string& name) { if(auto it = this->unresolvedGenericDefs.find(name); it != this->unresolvedGenericDefs.end()) return it->second; else return { }; } void StateTree::addDefinition(const std::string& name, Defn* def, const TypeParamMap_t& gmaps) { this->definitions[name].push_back(def); } std::string Scope::string() const { return zfu::join(this->components(), "::"); } const std::vector& Scope::components() const { if(!this->cachedComponents.empty()) return this->cachedComponents; auto& ret = this->cachedComponents; const Scope* s = this; while(s && s->stree) { ret.push_back(s->stree->name); s = s->prev; } std::reverse(ret.begin(), ret.end()); return ret; } const Scope& StateTree::getScope() { if(!this->cachedScope.stree) { this->cachedScope.stree = this; if(this->parent) this->cachedScope.prev = &this->parent->getScope(); } return this->cachedScope; } const Scope& Scope::appending(const std::string& name) const { return this->stree->findOrCreateSubtree(name)->getScope(); } void TypecheckState::teleportInto(const Scope& scope) { this->teleportationStack.push_back(this->stree); this->stree = scope.stree; } void TypecheckState::teleportOut() { this->stree = this->teleportationStack.back(); this->teleportationStack.pop_back(); } StateTree* StateTree::findSubtree(const std::string& name) { if(auto it = this->subtrees.find(name); it != this->subtrees.end()) return it->second; // check our imports, and our imports' reexports. for(const auto imp : this->imports) { if(imp->name == name) return imp; for(const auto exp : imp->reexports) if(exp->name == name) return exp; } return nullptr; } StateTree* StateTree::findOrCreateSubtree(const std::string& name, bool anonymous) { if(auto it = this->subtrees.find(name); it != this->subtrees.end()) { return it->second; } else { auto newtree = util::pool(name, this, anonymous); newtree->moduleName = this->moduleName; this->subtrees[name] = newtree; return newtree; } } std::vector TypecheckState::getDefinitionsWithName(const std::string& name, StateTree* tree) { if(tree == 0) tree = this->stree; std::vector ret; iceAssert(tree); while(tree) { auto fns = tree->getDefinitionsWithName(name); if(fns.size() > 0) return fns; tree = tree->parent; } return ret; } ErrorMsg* TypecheckState::checkForShadowingOrConflictingDefinition(Defn* defn, std::function conflictCheckCallback, StateTree* tree) { if(tree == 0) tree = this->stree; // first, check for shadowing bool didWarnAboutShadow = false; auto _tree = tree->parent; while(_tree) { if(auto defs = _tree->getDefinitionsWithName(defn->id.name); defs.size() > 0) { if(false && !didWarnAboutShadow) { didWarnAboutShadow = true; warn(defn, "definition of %s '%s' shadows one or more previous definitions", defn->getKind(), defn->id.name); for(auto d : defs) info(d, "previously defined here:"); } } _tree = _tree->parent; } auto makeTheError = [](Locatable* a, const std::string& n, const std::string& ak, const std::vector>& conflicts) -> SimpleError* { auto err = SimpleError::make(a->loc, "duplicate definition of '%s'", n); bool first = true; for(const auto& [ l, kind ] : conflicts) { err->append(SimpleError::make(MsgType::Note, l->loc, "%shere%s:", first ? strprintf("conflicting %s ", zfu::plural("definition", conflicts.size())) : "and ", ak == kind ? "" : strprintf(" (as a %s)", kind))); first = false; } return err; }; // ok, now check only the current scope auto defs = tree->getDefinitionsWithName(defn->id.name); for(auto otherdef : defs) { if(!otherdef->type->containsPlaceholders() && conflictCheckCallback(this, otherdef)) { auto errs = makeTheError(defn, defn->id.name, defn->getKind(), { std::make_pair(otherdef, otherdef->getKind()) }); // TODO: be more intelligent about when we give this informative tidbit if(dcast(sst::FunctionDecl, otherdef) && dcast(sst::FunctionDecl, defn)) { auto a = dcast(sst::FunctionDecl, defn); auto b = dcast(sst::FunctionDecl, otherdef); if(fir::Type::areTypeListsEqual(zfu::map(a->params, [](const auto& p) -> fir::Type* { return p.type; }), zfu::map(b->params, [](const auto& p) -> fir::Type* { return p.type; }))) { errs->append(BareError::make(MsgType::Note, "functions cannot be overloaded over argument names or" " return types alone")); } } return errs; } } // while in the interests of flexibility we provide a predicate for users to specify whether or not the duplicate definition is // actually conflicting, for generics i couldn't be damned. //? to know for certain that a definition will conflict with a generic thing, either we are: // A: variable & generic anything // B: function & generic type // C: type & generic anything if(auto gdefs = tree->getUnresolvedGenericDefnsWithName(defn->id.name); gdefs.size() > 0) { if(auto fn = dcast(sst::FunctionDecl, defn)) { // honestly we can't know if we will conflict with other functions. // filter out by kind. auto newgds = zfu::filterMap(gdefs, [](ast::Parameterisable* d) -> bool { return dcast(ast::FuncDefn, d) == nullptr; }, [](ast::Parameterisable* d) -> std::pair { return std::make_pair(d, d->getKind()); } ); if(newgds.size() > 0) return makeTheError(fn, fn->id.name, fn->getKind(), newgds); } else { // assume everything conflicts, since functions are the only thing that can overload. return makeTheError(defn, defn->id.name, defn->getKind(), zfu::map(gdefs, [](ast::Parameterisable* d) -> std::pair { return std::make_pair(d, d->getKind()); }) ); } } // no error. return nullptr; } void TypecheckState::pushAnonymousTree() { static size_t _anonId = 0; this->pushTree(std::to_string(_anonId++), /* createAnonymously: */ true); } Scope::Scope(StateTree* st) { this->prev = 0; this->stree = st; } } ================================================ FILE: source/typecheck/unions.cpp ================================================ // unions.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "errors.h" #include "typecheck.h" #include "ir/type.h" #include "memorypool.h" // defined in typecheck/structs.cpp void checkFieldRecursion(sst::TypecheckState* fs, fir::Type* strty, fir::Type* field, const Location& floc); void checkTransparentFieldRedefinition(sst::TypecheckState* fs, sst::TypeDefn* defn, const std::vector& fields); TCResult ast::UnionDefn::generateDeclaration(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) { fs->pushLoc(this); defer(fs->popLoc()); auto [ success, ret ] = this->checkForExistingDeclaration(fs, gmaps); if(!success) return TCResult::getParametric(); else if(ret) return TCResult(ret); auto defnname = util::typeParamMapToString(this->name, gmaps); bool israw = this->attrs.has(attr::RAW); sst::TypeDefn* defn = 0; if(israw) defn = util::pool(this->loc); else defn = util::pool(this->loc); defn->bareName = this->name; defn->attrs = this->attrs; defn->id = Identifier(defnname, IdKind::Type); defn->id.scope = this->enclosingScope; defn->visibility = this->visibility; defn->original = this; defn->enclosingScope = this->enclosingScope; defn->innerScope = this->enclosingScope.appending(defnname); if(israw) defn->type = fir::RawUnionType::createWithoutBody(defn->id.convertToName()); else defn->type = fir::UnionType::createWithoutBody(defn->id.convertToName()); if(auto err = fs->checkForShadowingOrConflictingDefinition(defn, [](auto, auto) -> bool { return true; })) return TCResult(err); defn->enclosingScope.stree->addDefinition(defnname, defn, gmaps); this->genericVersions.push_back({ defn, fs->getGenericContextStack() }); fs->typeDefnMap[defn->type] = defn; return TCResult(defn); } TCResult ast::UnionDefn::typecheck(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) { fs->pushLoc(this); defer(fs->popLoc()); auto tcr = this->generateDeclaration(fs, infer, gmaps); if(tcr.isParametric()) return tcr; else if(tcr.isError()) error(this, "failed to generate declaration for union '%s'", this->name); if(this->finishedTypechecking.find(tcr.defn()) != this->finishedTypechecking.end()) return TCResult(tcr.defn()); sst::TypeDefn* ret = 0; if(this->attrs.has(attr::RAW)) { auto defn = dcast(sst::RawUnionDefn, tcr.defn()); iceAssert(defn); fs->teleportInto(defn->innerScope); //* in many ways raw unions resemble structs rather than tagged unions //* and since we are using sst::StructFieldDefn for the variants, we will need //* to enter the struct body. auto unionTy = defn->type->toRawUnionType(); fs->pushSelfContext(unionTy); util::hash_map types; util::hash_map fields; auto make_field = [fs, unionTy](const std::string& name, const Location& loc, pts::Type* ty) -> sst::StructFieldDefn* { auto vdef = util::pool(loc); vdef->immut = false; vdef->name = name; vdef->initialiser = nullptr; vdef->type = ty; vdef->isField = true; auto sfd = dcast(sst::StructFieldDefn, vdef->typecheck(fs).defn()); iceAssert(sfd); if(fir::isRefCountedType(sfd->type)) error(sfd, "reference-counted type '%s' cannot be a member of a raw union", sfd->type); checkFieldRecursion(fs, unionTy, sfd->type, sfd->loc); return sfd; }; std::vector tfields; std::vector allFields; for(auto variant : this->cases) { auto sfd = make_field(variant.first, std::get<1>(variant.second), std::get<2>(variant.second)); iceAssert(sfd); fields[sfd->id.name] = sfd; types[sfd->id.name] = sfd->type; allFields.push_back(sfd); } // do the transparent fields { size_t tfn = 0; for(auto [ loc, pty ] : this->transparentFields) { auto sfd = make_field(fir::obfuscateName("transparent_field", tfn++), loc, pty); iceAssert(sfd); sfd->isTransparentField = true; // still add to the types, cos we need to compute sizes and stuff types[sfd->id.name] = sfd->type; tfields.push_back(sfd); allFields.push_back(sfd); } } checkTransparentFieldRedefinition(fs, defn, allFields); defn->fields = fields; defn->transparentFields = tfields; unionTy->setBody(types); fs->popSelfContext(); ret = defn; } else { auto defn = dcast(sst::UnionDefn, tcr.defn()); iceAssert(defn); fs->teleportInto(defn->innerScope); util::hash_map> vars; std::vector> vdefs; iceAssert(this->transparentFields.empty()); for(auto variant : this->cases) { vars[variant.first] = { std::get<0>(variant.second), (std::get<2>(variant.second) ? fs->convertParserTypeToFIR(std::get<2>(variant.second)) : fir::Type::getVoid()) }; auto vdef = util::pool(std::get<1>(variant.second)); vdef->parentUnion = defn; vdef->variantName = variant.first; vdef->id = Identifier(defn->id.name + "::" + variant.first, IdKind::Name); vdef->id.scope = fs->scope(); vdefs.push_back({ vdef, std::get<0>(variant.second) }); fs->stree->addDefinition(variant.first, vdef); defn->variants[variant.first] = vdef; } auto unionTy = defn->type->toUnionType(); unionTy->setBody(vars); // in a bit of stupidity, we need to set the type of each definition properly. for(const auto& [ uvd, id ] : vdefs) uvd->type = unionTy->getVariant(id); ret = defn; } iceAssert(ret); this->finishedTypechecking.insert(ret); fs->teleportOut(); return TCResult(ret); } ================================================ FILE: source/typecheck/using.cpp ================================================ // using.cpp // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "ast.h" #include "defs.h" #include "errors.h" #include "sst.h" #include "typecheck.h" #include "ir/type.h" #include "memorypool.h" TCResult ast::UsingStmt::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); // check what kind of expression we have. auto used = this->expr->typecheck(fs).expr(); if(!dcast(sst::ScopeExpr, used) && !dcast(sst::VarRef, used)) error(this->expr, "unsupported expression on left-side of 'using' declaration"); // check for enumerations -- we need to handle those a little specially. // due to the magic of good code architecture, (haha, who am i kidding, it's pure luck) // if the LHS is a dot operator of any kind, we'll resolve it appropriately -- getting a VarRef to an EnumDefn if it is an enum, // and only getting ScopeExpr if it's really a namespace reference. sst::Scope scopes; auto vr = dcast(sst::VarRef, used); if(vr && dcast(sst::EnumDefn, vr->def)) { auto enrd = dcast(sst::EnumDefn, vr->def); scopes = enrd->innerScope; } // uses the same 'vr' from the branch above else if(vr && dcast(sst::UnionDefn, vr->def)) { auto unn = dcast(sst::UnionDefn, vr->def); scopes = unn->innerScope; } else { sst::TypeDefn* td = nullptr; // this happens in cases like `foo::bar` if(auto se = dcast(sst::ScopeExpr, used)) scopes = se->scope; // and this happens in cases like `foo` else if(vr && (td = dcast(sst::TypeDefn, vr->def))) scopes = td->innerScope; else error("unsupported LHS of using: '%s'", used->readableName); } auto target = scopes.stree; while(target->proxyOf) target = target->proxyOf; if(this->useAs == "_") { sst::mergeExternalTree(this->loc, "using", fs->stree, target); } else { // check that the current scope doesn't contain this thing if(auto existing = fs->getDefinitionsWithName(this->useAs); existing.size() > 0) { auto err = SimpleError::make(this->loc, "cannot use scope '%s' as '%s'; one or more conflicting definitions exist", scopes.string(), this->useAs); err->append(SimpleError::make(MsgType::Note, existing[0]->loc, "first conflicting definition here:")); err->postAndQuit(); } auto tree = fs->stree->findOrCreateSubtree(this->useAs); sst::mergeExternalTree(this->loc, "using", tree, target); } return TCResult::getDummy(); } ================================================ FILE: source/typecheck/variable.cpp ================================================ // variable.cpp // Copyright (c) 2014 - 2017, zhiayang // Licensed under the Apache License Version 2.0. #include "defs.h" #include "pts.h" #include "ast.h" #include "errors.h" #include "sst.h" #include "typecheck.h" #include "resolver.h" #include "polymorph.h" #include "ir/type.h" #include "memorypool.h" static TCResult getResult(ast::Ident* ident, sst::Defn* def, bool implicit = false) { auto ret = util::pool(ident->loc, def->type); ret->name = ident->name; ret->def = def; ret->isImplicitField = implicit; return TCResult(ret); } static TCResult checkPotentialCandidate(sst::TypecheckState* fs, ast::Ident* ident, sst::Defn* def, fir::Type* infer) { bool implicit = false; if(auto fld = dcast(sst::StructFieldDefn, def)) { implicit = true; // check that we're actually in a method def. //* this is superior to the previous 'isInStructBody()' approach, because this will properly handle defining nested functions //* -- those are technically "in" a function body, but they're certainly not methods. if(!fs->isInFunctionBody() || !fs->getCurrentFunction()->parentTypeForMethod) { return TCResult( SimpleError::make(ident->loc, "field '%s' is an instance member of type '%s', and cannot be accessed statically", ident->name, fld->parentType->id.name) ->append(SimpleError::make(MsgType::Note, def->loc, "field '%s' was defined here:", def->id.name)) ); } } // check if we're not doing something stupid! if(auto vd = dcast(sst::VarDefn, def)) { if(fs->isInFunctionBody() && vd->definingFunction && vd->definingFunction != fs->getCurrentFunction()) { return TCResult( SimpleError::make(ident->loc, "invalid reference to variable '%s', which was defined in another function", ident->name) ->append(SimpleError::make(MsgType::Note, vd->loc, "'%s' was defined here:", ident->name)) ->append(BareError::make(MsgType::Note, "variable capturing (ie. closures) are currently not supported")) ); } } if(def->type->isUnionVariantType()) { auto uvd = dcast(sst::UnionVariantDefn, def); iceAssert(uvd); if(uvd->type->containsPlaceholders() || uvd->parentUnion->type->containsPlaceholders()) { std::vector fake_args; auto res = sst::resolver::resolveAndInstantiatePolymorphicUnion(fs, uvd, &fake_args, infer, /* isFnCall: */ /* uvd->type->toUnionVariantType()->getInteriorType()->isVoidType() ? true : */ false); if(res.isError()) return TCResult(res); // update uvd uvd = dcast(sst::UnionVariantDefn, res.defn()); } // see the explanation in ast.h for ident flag. if(ident->checkAsType) { // make sure the types match, at least. if(infer && uvd->parentUnion->type != infer) { if(!infer->isUnionType()) { return TCResult(SimpleError::make(ident->loc, "non-union type '%s' inferred for variant '%s' of union '%s'", infer, ident->name, uvd->parentUnion->type) ); } else { return TCResult(SimpleError::make(ident->loc, "inferred union '%s' cannot yield variant '%s' of unrelated union '%s'", infer, ident->name, uvd->parentUnion->type) ); } } return getResult(ident, uvd, implicit); } else { auto ret = util::pool(ident->loc, uvd->parentUnion->type); ret->variantId = uvd->parentUnion->type->toUnionType()->getIdOfVariant(uvd->variantName); ret->parentUnion = uvd->parentUnion; ret->args = { }; return TCResult(ret); } } else if(infer && def->type->containsPlaceholders()) { auto fd = dcast(sst::FunctionDefn, def); iceAssert(fd); std::vector infer_args; auto [ res, soln ] = sst::poly::attemptToInstantiatePolymorph(fs, fd->original, fd->id.name, { }, /* return_infer: */ nullptr, /* type_infer: */ infer, /* isFnCall: */ false, &infer_args, /* fillPlacholders: */ false, /* problem_infer: */ def->type); if(res.isError()) return TCResult(res); else return getResult(ident, res.defn(), implicit); } return getResult(ident, def, implicit); } TCResult ast::Ident::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); if(this->name == "_") { return TCResult( SimpleError::make(this->loc, "'_' is a discarding binding; it does not yield a value and cannot be referred to") ); } auto makeScopeExpr = [this](const sst::Scope& scope) -> sst::ScopeExpr* { return util::pool(this->loc, fir::Type::getVoid(), scope); }; if(this->name == "::") { // find the root. auto t = fs->stree; while(t->parent) t = t->parent; return TCResult(makeScopeExpr(t->getScope())); } else if(this->name == "^") { if(!fs->stree->parent) { return TCResult( SimpleError::make(fs->loc(), "invalid use of '^' at the topmost scope '%s'", fs->stree->name) ); } else { auto t = fs->stree->parent; while(t->isAnonymous && t->parent) t = t->parent; return TCResult(makeScopeExpr(t->getScope())); } } if(auto builtin = fir::Type::fromBuiltin(this->name)) return TCResult(util::pool(this->loc, builtin)); if(infer && infer->containsPlaceholders()) infer = 0; if(this->name == "this" && fs->isInFunctionBody() && fs->getCurrentFunction()->parentTypeForMethod) return TCResult(util::pool(this->loc, fs->getCurrentFunction()->parentTypeForMethod)); // hm. sst::StateTree* tree = fs->stree; while(tree) { if(auto vs = tree->getDefinitionsWithName(this->name); vs.size() == 1) { return checkPotentialCandidate(fs, this, vs[0], infer); } else if(vs.size() > 1) { std::vector> ambigs; for(auto v : vs) { auto res = checkPotentialCandidate(fs, this, v, infer); ambigs.push_back({ v, res }); } if(ambigs.size() == 1) { return ambigs[0].second; } else { std::vector> fails; std::vector> succs; for(const auto& v : ambigs) { if(v.second.isError()) fails.push_back(v); else succs.push_back(v); } if(succs.empty()) { auto errs = SimpleError::make(this->loc, "no definition of '%s'%s", this->name, infer ? strprintf(" matching type '%s'", infer) : ""); for(const auto& v : succs) errs->append(v.second.error()); return TCResult(errs); } else if(succs.size() > 1) { auto errs = SimpleError::make(this->loc, "ambiguous reference to '%s'", this->name); for(const auto& v : succs) errs->append(SimpleError::make(MsgType::Note, v.first->loc, "potential target here:", v.first)); return TCResult(errs); } else { return getResult(this, succs[0].first, false); } } } else if(auto gdefs = tree->getUnresolvedGenericDefnsWithName(this->name); gdefs.size() > 0) { std::vector fake; auto pots = sst::poly::findPolymorphReferences(fs, this->name, gdefs, this->mappings, /* return_infer: */ 0, /* type_infer: */ infer, /* isFnCall: */ false, &fake); if(pots.size() > 1) { auto err = SimpleError::make(this->loc, "ambiguous reference to '%s', potential candidates:", this->name); for(const auto& p : pots) err->append(SimpleError::make(p.res.defn()->loc, "")); return TCResult(err); } else { iceAssert(pots.size() == 1); if(pots[0].res.isDefn()) return getResult(this, pots[0].res.defn()); else return pots[0].res; } } // check if there is a subtree with this name. if(auto it = tree->subtrees.find(this->name); it != tree->subtrees.end()) return TCResult(makeScopeExpr(it->second->getScope())); if(this->traverseUpwards) tree = tree->parent; else break; } // ok, we haven't found anything return TCResult( SimpleError::make(this->loc, "reference to unknown entity '%s'", this->name) ); } TCResult ast::VarDefn::typecheck(sst::TypecheckState* fs, fir::Type* infer) { fs->pushLoc(this); defer(fs->popLoc()); // ok, then. sst::VarDefn* defn = 0; if(this->isField) { auto fld = util::pool(this->loc); fld->parentType = fs->typeDefnMap[fs->getCurrentSelfContext()]; iceAssert(fld->parentType); defn = fld; } else { defn = util::pool(this->loc); } // check for people being stupid. if(this->name == "this" && fs->isInFunctionBody() && fs->getCurrentFunction()->parentTypeForMethod) return TCResult(SimpleError::make(this->loc, "invalid redefinition of 'this' inside method body")); iceAssert(defn); defn->bareName = this->name; defn->attrs = this->attrs; defn->id = Identifier(this->name, IdKind::Name); defn->id.scope = fs->scope(); defn->immutable = this->immut; defn->visibility = this->visibility; defn->global = !fs->isInFunctionBody(); if(this->type != pts::InferredType::get()) defn->type = fs->convertParserTypeToFIR(this->type); else if(!this->initialiser) error(this, "initialiser is required for type inference"); //* for variables, as long as the name matches, we conflict. if(auto err = fs->checkForShadowingOrConflictingDefinition(defn, [](auto, auto) -> bool { return true; })) return TCResult(err); // check the defn if(this->initialiser) { defn->init = this->initialiser->typecheck(fs, defn->type).expr(); if(defn->init->type->isVoidType()) error(defn->init, "value has void type"); if(defn->type == 0) { auto t = defn->init->type; if(t->isConstantNumberType()) t = sst::inferCorrectTypeForLiteral(defn->init->type->toConstantNumberType()); defn->type = t; } else if(fir::getCastDistance(defn->init->type, defn->type) < 0) { SpanError::make(SimpleError::make(this->loc, "cannot initialise variable of type '%s' with a value of type '%s'", defn->type, defn->init->type)) ->add(util::ESpan(defn->init->loc, strprintf("type '%s'", defn->init->type))) ->postAndQuit(); } } if(this->name != "_") fs->stree->addDefinition(this->name, defn); // store the place where we were defined. if(fs->isInFunctionBody()) defn->definingFunction = fs->getCurrentFunction(); return TCResult(defn); }